Exporting Servlet Data to Excel

February 10th, 2010

I had a user that liked the pages I'd created in my web app, but they really needed to be able to export the data to Excel so they didn't have to transcribe it. Makes sense, and given that I know Excel takes CSV data, and the DataTable I wrote in Java has an option to output CSV, it should be easy.

Well... that was a good idea... but it really wasn't too hard once you get a few things cleared up. First, the CSV format. I had my CSV output method, toCSV(), formatting the numbers which was a terrible mistake. I needed to stop that. Then I needed to escape the CSV data according to these basic CSV rules:

  • if the data has a comma in it - surround it with double-quotes
  • if the data has a double-quote in it, double it, and then surround it with double-quotes

The first one is obvious. If I have data like this:

32.5 Reggie Indianapolis, IN 5

then the CSV needs to look like:

  32.5,Reggie,"Indianapolis, IN",5

and if I had data like this:

32.5 Reggie "Dog" Johnson Indianapolis, IN 5

then the CSV needs to look like:

  32.5,"Reggie ""Dog"" Johnson","Indianapolis, IN",5

OK, these were new little wrinkles for me, but it didn't take too much time to make these fixes to my DataTable Java class. Now I have the right format, but how do I set up the rest of the response so I have Excel automatically handle it without a lot of grief?

Well... it turns out it's the header and content type. Each of my servlet requests has a parameter associated with them called out. If it's json, then the output of the request is JSON. If it's html, then it's HTML. This really helps in the debugging of the servlets as I can add &out=html... to the URL and see the results in the browser. Nice.

Well... let's make another 'type' of out - excel. Then, in my servlet I can do the following:

  String   out = request.getParameter("out");
  if (out == null) {
    out = "html";
  }
 
  if (out.equalsIgnoreCase("json") || out.equalsIgnoreCase("html")) {
    response.setContentType("text/html");
  } else if (out.equalsIgnoreCase("csv")) {
    response.setContentType("text/csv");
  } else if (out.equalsIgnoreCase("excel")) {
    response.setHeader("Content-disposition", "attachment;filename=\"myDump.csv\"");
    response.setContentType("application/vnd.ms-excel");
  }

I was lucky to get the header and content type from a few google searches, and then it was just a matter of putting it all together. Once I get my DataTable I can then ship it back to the caller with the code:

  if (out.equalsIgnoreCase("json")) {
    response.print(ans.toJSON());
  } else if (out.equalsIgnoreCase("csv") || out.equalsIgnoreCase("excel")) {
    response.print(ans.toCSV());
  } else {
    response.print("<center>" + ans.toHTML() + "</center>");
  }

When I put this all together, the client doesn't need to know a thing. The request comes in for the URL, and the data comes back, intercepted by Excel, and it fills in the cells. Pretty neat.

Holding Onto Those Magical Moments

February 10th, 2010

Today I knew that Marie was glad I was her Dad. She called this morning and had a problem with Pages '09 and an outline she had been writing as a homework assignment. She had accidentally compressed the outline into "one line per item" mode, and was in a bit of a panic because she needed to have it printed out for today.

I looked at what she was doing, then we went through all the menu bar settings and at the very right, there it was. Click that, and she was in business.

The relief in her voice was something I'll remember for a long time. Moments like this - where you can tell that one of your kids is really, honestly, grateful that they are your kid, are few and far between for teenagers. It was something I really enjoyed.

Debugging JavaScript Memory Usage with Google Chrome

February 9th, 2010

I've got some massive web pages - lots of AJAX requests feeding thousands of data points back to the client for inclusion into some Google Visualization widgets - it's as heavy-duty as many visualization apps I've created. But therein lies a problem - memory usage.

One of my users wants to have a dozen of these pages open and hammering away all day long, and while that's nice, it's not a good idea from the resource consumption angle. It would be ideal if there were a JavaScript event that told me when the view was completely hidden. But I've looked for that and there's nothing I can find that is going to tell me when to shut down the updating, or when to start it back up again.

So I need to do some memory profiling of the pages and try to figure out why they are getting out of hand. So I started digging into what Google Chrome had, and was pleased to see that it was really WebKit that had what I needed. Well... close, anyway.

Within Chrome, there are a lot of nice tools to show you what's happening. Not a lot of help when dealing with Google Visualization widgets as their code goes through an 'optimizer' and the objects are then pretty useless for help, but it tells me that the problem is most likely in their stuff and the Strings that are being created in the moving of data back and forth between the server.

None of this is really Rocket Science, but it's nice to have quick access to the tools to be able to see the difference in a few memory dumps, and even a little code profiling. Not bad at all.

Finishing Up the Massive Data Organization

February 8th, 2010

Today I spent the entire day cleaning up a few things that I forgot about the data from the Hemlock database, and then writing the Java loader of that data so that it's all loaded when it's needed, updated on a decent interval (love that database polling) and then available in a reasonably decent way to the servlets that will need it.

Lots of heads down coding today.

Organizing Lots and Lots of Data

February 5th, 2010

Today was spent digging into the SQL of the Hemlock database and trying to find the data the users are asking for, then trying to organize it in the servlet so that it's possible to access what we need very quickly and with a minimum of fuss. Given the way these things are laid out, I was stunned that I got as far along today as I did.

I was able to get the stored procedures written to pull the data for today, and the last week (to give you a hint, I have to go to one database for one, and another database for the other). I was also able to get the product data and the month/strike data. Really... I was pretty impressed with what I was able to get done.

Heads down... it can pay off.

Interesting Alternative to VLC – Movist

February 5th, 2010

Today Gruber pointed out a link to an Open Source alternative to VLC. Given that VLC is hurting for the Mac developers, and that it's not able to even get a 64-bit version out the door, it seems likely that it might be heading out. If that's the case, then ripping DVDs is going to get very hard.

Movist seems to be nice, small, clean, and it works. Can't ask a lot more than that. I'll see if I need it, but it doesn't have the libdvdcss.2.dylib that HandBrake et. al. need to function. That's not a good sign.

Once more unto the breach – Facing Horrible Code Once More

February 4th, 2010

Wonderful quote - horrible feeling if there's nothing to be gained. In this case, there wasn't. I had to once again dig into what I'm now calling Project Hemlock, the project I was given very early on at this job, and once again the lack of any documentation either written or comments in the code makes this a challenge I'd not wish to have.

There's something broken in a part of the Hemlock web app, and I need to fix it, but it's not a simple page - it's got business logic in the Flex client as well as the servlet gathering the data for the Flex client. It's not got a clear layout as to what it's doing or why, so the only way to follow the logic is to read each line of the code, understand what the variables are, why this might be happening, and then infer the function.

This logical single-stepping is very tiresome, and today I leave with very little done - more a point of a little more understanding, but still not enough to know where the problem is, or how to fix it. The only way I'm going to get this figured out is to pull in the original developer tomorrow, and have him tell me what's going on.

It's almost funny, but it's not. It's sad.

The Dangers of ‘Good Enough’

February 3rd, 2010

I was talking to a co-worker yesterday about several things that are scheduled for the coming year, and we got around to a very significant re-write that I've advocated for about as long as I've been at the Shop. It's something that's needed very badly, but the problem is that it would take several months to get a re-write to the point of the existing application (which I support). This delay of months for "nothing" new, while it's still possible to add things to the old application, makes it a very hard sell. So hard, in fact, that I've become convinced that it'll never happen.

Really? You ask.

Really.

Why? You ask, and I'll be glad to tell you.

'Good enough' is the Enemy of Great. - Anonymous

Doesn't sound right, and in fact, the original saying is French:

'Better' is the Enemy of 'Good Enough'

and that is true, but anything - taken to an extreme, is bad. And this motto is no exception. Imagine this: a company starts off small, hungry, willing to take risks to get things done. They succeed, they grow, and life is good. Now the company is doing "good enough". It could certainly be worse - many people are still there that remember the lean days. So the willingness to risk like they did in the past is lost. They don't want to risk the "good enough" for the possibility that things get worse.

There's nothing wrong with this... it's up to the people involved. If you have achieved something, and wish to protect it, there's nothing wrong with that. But don't fool yourself. Someone out there is going to be in the same place you once were, and they will be ready, and willing, to risk a little in order to gain a little more. If you can protect your gains, that's great. But if you're still in a competitive environment, you've just become the target, and you're standing still.

Dead meat.

So rather than grow, you stagnate. Maybe that's OK, and you get out of the business altogether. Lots do. Nothing wrong with it. But if you expect to stay a leader, then you need to act like a leader, and that means you need to continue to improve and take the same kind of (appropriate) risks that you did to get to this point.

Our conversation got to this point on many fronts of the Shop. It seemed very puzzling to me why this would be the case with the original founders still with the company. Why would they stop? And as I was thinking about it, it might be because they (and others) are still with the Shop.

They all remember the "bad days", and so are fearful of returning to them. They aren't thinking that today is a new baseline for the future. They're probably thinking that today is 'good enough' - compared to not too long ago. And that's not a good philosophy to run a business by. Pretty soon, your competitors are going to make your 'good enough' a lot more like the 'bad old days' because you're too fearful of the kind of risk that got you to this place in the beginning.

As a university professor, I didn't understand why a university would not hire someone that got all their degrees from that school. I mean, who better to lead the school than someone that's been through it? But that's exactly the person you don't want. Get some new blood in there... see the world from a different perspective... refine the vision. If you're managing people in an international business and the only place you've ever worked is the one employer, then you're doing everyone a grave disservice. You need to move on.

Of course, this isn't welcome opinion, but it's good advice. You are a product of the environment, and as it has grown, you have grown, but you have no basis of comparison for your actions. When people come in to a business, and you only know how this one place functions, you have no idea what they are expecting. Even if you ask them, the myopic views you'll have will end up causing the 'good enough' to slip in and degrade the business.

There was a question I didn't understand when taking all those entrepreneur tests - What's your exit strategy?. Mine was always: Retire, but that's a bad plan, and it misses the reason for the strategy: an exit. If it gets really successful, you are most likely going to have to take yourself out of the day-to-day operation as it's going to outgrow you. I see it now, and I'll be sure not to make that mistake, but it's a lesson I think several people here should take to heart.

iPhone OS 3.1.3 Firmware Update on iTunes

February 3rd, 2010

iPhone3GS.jpg

This morning I noticed that Apple released iPhone OS 3.1.3 through iTunes, and it includes the nice feature that the battery monitor is supposed to be more accurate - which is good, even if the time I can use it is shorter. I need to plan what I can do with my phone, and this is just essential information to that planning. There were other security fixes, which is great, and I was always going to upgrade, it's just nice to know what it was about.

Unison 2.0.4 is Out

February 3rd, 2010

I got an email (as a beta tester) from Cabel for Unison 2.0.4. Seems there were a few issues with the PPC support, and he wanted folks to test it before releasing it. I got it and my old issue of a GUI imperfection is still there, but I got a reply from them about this and know that they are working on it as time permits. This morning, I got a

I love their applications, and can only hope that the way they code is as elegant. Wonderful work.