Busted Mug

A blog that documents solutions to the most frustrating problems that occur during development in technologies such as Java, XML, AJAX, SQL, CSS and others that make me want to throw my coffee mug against the cube wall.

Monday, June 02, 2008

Dumping a mysql database - piece of cake

I love MySql. A lot. No muss, no fuss. It just gets the job done. Granted I am not supporting it on an enterprise level (as the argument usually goes from the pro-proprietary), but it really fits my needs great.

Case in point: I had a prototype project hosted on some hardware that was incurring cost. Being that the prototype had outlived it's usefulness I wanted to back up my code but then un-host it and get rid of the hardware. Since the project was quite simple, I had done the MySql DB work myself (I'm usually a java developer but I was DB admin as well on this LAMP project). Now it came time to back up the database.

I googled for backing up a MySql database and found this. It simply outlines the utility included with MySql that accomplishes my purpose. I ran a simple:

mysqldump -u root -p Complaints > complaints.sql

Bam! All done! 5 minutes tops. Data and structure backed up and ready to be re-instantiated at my bidding. Hence, I love MySql.

Labels: , ,

Tuesday, March 25, 2008

Database operation failed. ERROR: library routine called out of sequence DETAILS: not an error

I ran into this guy "Database operation failed. ERROR: library routine called out of sequence DETAILS: not an error" while working on a google gears application. The error comes from SQL Lite (the technology under the sheets of gears' data store). There didn't seem to be much documentation on the web to help but finally from placing lots of alert statements (don't you love javascript?) I narrowed it down to a call to rs.next(). I knew the data set would be empty so I immediately suspected I was doing something wrong with checking for the end of the RS.

My suspicions were confirmed when I found the following code block at http://code.google.com/apis/gears/api_database.html#ResultSet:

while (rs.isValidRow()) { console.log(rs.fieldName(0) + " == " + rs.field(0)); rs.next(); } rs.close();

It appears I missed something basic. Unlike both Oracle and MySQL, when grabbing a new row in SQL Lite in Gears there isn't any automatic evaluation that the row is valid. You have to explicitly call the isValidRow() method. This leaves out the nice and tidy while(rs.next) loops that we all love so much. The first row comes pre-loaded then you have to next after each use. As the dude would say "That's a bummer, Man." I hope I head off someone else freaking out over this novice problem when working in Gears. Maybe SQL Lite/Gears will eliminate the need for the call some day, until then...

Saturday, March 01, 2008

Google answers online state dilemma with non-answer

As I discussed in my previous post There isn't a way to maintain online state with Google Gears. I just found an entry on Google Code which addresses the subject when it comes to database stores. I totally understand Google's point about wanting developers to ensure synchs are reliable and not assume online = success. That still doesn't address my issue with LocalServer rather than the Database module of Gears.

A bit frustrating also is to see that on the same page Google provides essentially the same code I discussed previously to ping the server with AJAX to verify that it is available. GaH! Wasted effort!

I have to say that I do think Google is cutting off it's nose to spite it's face here. While an isOnline() function might be abused when it comes to the local database, it's entirely necessary (as I've demonstrated) for the localServer which is 1/3 of the gears trinity. In addition, I've seen time and time again that you can't use technology to make programmers do their job correctly (I've tried). You have to empower them to make good design decisions on their own, warn them of the pitfalls, and then let them deal with the consequences if they don't do their job well. It's an annoying fact of life in IT (I would know, I've done a lot of cleanup after bad programmers). That's my 2 cents anyhow.

Labels: , , , , ,

Google gears and the online state dilemma

As I mentioned in my previous post I've been working with Google Gears as of late. Being a greenhorn to this technology (as nearly everyone is since it's pretty new) I found myself considering some fairly serious design questions. The most interesting was "how do I tell if a user is in offline mode (pages and data cached) but has the ability to switch over to online mode?"

Now of course whenever you talk about "modes" in an application it is natural to think about a state machine. That gets a little dicier with the new paradigm introduced with Gears. Since gears runs purely in javascript with a little interaction with the browser plugin, I decided that making an AJAX request for a file that doesn't get cached (as defined in my gears manifest file) was best. If I got the proper contents of that file then I knew the person could swap to online mode, if not then I know they aren't connected. Simple right?

So I thought. Once I whipped up my code I could offline and online my pc and the app was stateful, except of course for a little lag that the ajax request took to timeout when it wasn't ever going to get a response from the server. I included validation based on state to see if I would let the user remove their cached pages and get the online one and everything was happy.

Then I decided to take a look at what I'd done pretending to be a non-technical user. I offlined my app and then watched it. During the lag I noticed that the app state was still online (meaning you could validly switch to online mode) because the first AJAX request hadn't failed yet. So I thought to myself "what if the user took this literally and assumed they were connected via wifi or something and tried to go online?"

The answer: DEATH. Ok not really death but my state machine happily checked its state, saw that it was online, removed all the cached pages and tried to get at the online version of the page. This of course resulted in a 404 as the user wasn't actually connected. No good. My first instinct was that I had to prevent this from ever being a possible scenario because a user would probably freak out.

The half-measure I took to do this was to break out the cache-removing code and not include it on the manifest. Now the user can attempt to remove their cache, but if they aren't actually online they won't find that page and get a 404, but they can back up and the app is still happily serving up cached content while they continue to be offline.

I'm happy with this but not completely. It seems to me (at least so far) that there's no way to conquer this part of the paradigm shift that gears introduces into web applications. No matter how you code around it, the web layer always has a degree of latency associated with it that will allow a window for 404 messages. I hate for the user to see that. I'll update if I figure out a way around this loophole, please comment if you know one ;)

Labels: , , , , , ,

Simple, cross-browser threading (forking) in php

I recently had a need to do some threaded processing in php while working on a Google Gears prototype application. As is often the case with gears, when synching the data with the online database, it'll take a while. If you're doing this explicitly and not in the background, it's nice to at least be able to update the user of the process' status using AJAX. This was my need for threading (forking in php). I wanted to run a thread to handle the update of the database and let the user sit on a page that keeps checking on the progress and updating a progress bar. Intuitive, right?

Since it had been a while since I've worked with forks in PHP I figured I'd check out Google for a tutorial on the best practice on the subject. Whoa. I got like 90 different methodologies and hardly any worked for all scenarios and cross-platform (I don't know if my project will end up on a server with windows under it or *nix). That is, until I found this blog entry by a chick named Katy. She demos the following code:



To create a fork:
function startFork($path, $file, $args)
{
  chdir($path);

  if (substr(PHP_OS, 0, 3) == 'WIN')
    $proc = popen('start /b php "' . $path . '\\' . $file . '" ' . $args, 'r');
  else
    $proc = popen('php ' . $path . '/' . $file . ' ' . $args . ' &', 'r');
 
  return $proc;
}

To get data from the fork:
while (!feof($proc)) {
  $data = fgets($proc);

  // Do something with the data
}
This methodology is great because it seems to always fit. It's pretty easy to understand too. It does involve some OS calls but has conditions for for windows and *nix, which is ok by me. It's a simple method that starts a new process for the thread. I plan to implement post haste. I'd recommend this if you need to do some threading (forking, I wish Java and PHP would get on the same page as far as terminology is concerned).

Labels: , , , , ,

Thursday, November 15, 2007

IE duplicates element IDs into the Name attribute, which screwed me up!

ARGH! This one really gets me steamed. It seems that IE has decided that rather than supporting the applicable W3C and ECMA standards, they do what made sense to them. Surprised? I'm not. Anyhow, what the world ends up being stuck with is a scenario where id attributes are mirrored into an invisible name attribute for form elements. Why? So some lazy javascript developer somewhere can erroneously use getElementById('x') to access an element that has the NAME "x" but no the ID "x". I'll spare you the departure into the fact that the frigging function says ID in it and there's another one that uses NAME explicitly. Such mastery of scripting is apparently too much to ask.

That on it's own is lazy, but not terrible. However it turns terrible when you've got some code like this:

<td id="range5"><input type="text" name="range5" /></td>

Now when you submit some perfectly reasonable HTML like this to a web server with a decent browser like firefox you get only 1 element named range5 as you'd expect because you only named one element range5. Try the same with IE and what you'll end up with is a few hours of debugging and cursing the MSoft name. At the end of said debugging you'll find that since IE mirrors the ID attribute into the name attribute (invisibly) The server actually is submitted 2 elements named range5, the first of which in this case has a null value. ARRRRRGH!

So then what is the world left to do about such idiocracy (excellent movie by the by, look it up)? Well, I for one am going to dutifully note this in my "things that suck about IE to think about when coding" list that I always have running around in my head, and not name any IDs the same as NAMEs even though those are supposed to be two distinct entities with no relationship what so ever. IE sucks.

Labels: , , , , ,

Wednesday, November 07, 2007

AJAX and multi-lingual apps (i18n)

I found a great list of AJAX mistakes (http://swik.net/Ajax/Ajax+Mistakes) in the course of making one. When dealing with mutli-lingual apps you need to use the UTF-8 char set as it provides umlauts and tilde's for spanish and german (just to name a few). The obvious implementation is to set this on your HTML response. The easy part to miss though is to set them in ajax as Ajax Mistakes points out:

Character Sets

One big problem with using AJAX is the lack of support for character sets. You should always set the content character set on the server-side as well as encoding any data sent by Javascript. Use ISO-8859-1 if you use plain english, or UTF-8 if you use special characters, like æ, ø and å (danish special characters) Note: it is usually a good idea to go with utf-8 nowadays as it supports many languages).
As it turned out I needed to set the content type of my response to include the UTF-8 character set like so:
response.setContentType("text/html; charset=utf-8");
Then my AJAX response came through with valid characters, yay!

Labels: , , ,

Monday, March 19, 2007

Busted Mug: Dynamic Assignment of Event Handlers - A generic rollover event

Busted Mug: Dynamic Assignment of Event Handlers - A generic rollover event - Gosh, what was I thinking? You've gotta preload those rollovers! Here's a revised version using a dynamically created function as the dynamically created event handler. Say that ten times fast...you'll probably want to dynamically go create yourself a cup of coffee ;)
//bch: better code for rollovers
function start(){
    var els = document.getElementsByTagName('img');
    for (i=0; i<els.length; i++){
        if(els[i].className 
== "rollover"){ 
            var tmp 
= new Image();
            
            //save out source
            tmp.src 
= els[i].src;
            outs[i] 
= tmp;
            
            //save over source
            tmp.src 
= els[i].substring(0,src.length-4) + "_over" + src.substring(src.length-4);
            overs[i] 
= tmp;
        
            //set event handlers w/ dynamic functions
            els[i].onmouseover 
= eval(new function (){ this.src = overs[i].src});
            els[i].onmouseout 
= eval(new function (){ this.src = outs[i].src});
        }
    }
}

Friday, March 16, 2007

Double killer delete select all


Oh it burns so good! It reminds me of this classic windows 98 debachle

Mystery white space before a table

I was trying to debug some mystery white space that was appearing on a page before a table. For some reason the source code showed nothing before the table, but the display didn't agree.

Using FireBug (an add-on to firefox that i HIGHLY recommend) I was able to see that FFox thought that white space should be there because of some BR tags. Curious. I couldn't find them anywhere.

Finally tracing through I ran into a much more obfuscated version of this:

out.println("<table>");
for 
(int i=0i<contents.lengthi++){
    
out.println("<tr><td>" + contents[i] + "</td></tr><br>");
}

Note the BR on the end there. That's not valid. Apparently FFox handled this bad code by kicking the BRs to the head of the table. A simple fix to a problem that had me in mug busting mood BIG TIME.