Friday, December 19, 2008

Getting JRuby running on Ubuntu

Here's a link to someone who did a good job showing what to do to install JRuby on Ubuntu (the version on 8.04 seems to be jruby1.0 which is significantly out of date and was not allowing me to install any gems)

http://dermological.blogspot.com/2007/02/installing-jruby-on-ubuntu.html

Tuesday, December 9, 2008

Interesting Ruby comparison

I haven't really had time to digest this yet, but JRuby seems to be up there in the speed dept...

http://antoniocangiano.com/2008/12/09/the-great-ruby-shootout-december-2008/

Friday, December 5, 2008

Ok, so while the Java language itself has lost some of it's luster for me, I still love the JVM. Here's a very common scenario:
  1. query a database and create an xml file from the dataset using tag names that you provide and write it to a file.

Not saying it can't be done quickly or cleanly in Java, but think how long it would take/how lines of (almost boilerplate) code...

Groovy to the rescue...

import org.ho.yaml.Yaml
import groovy.sql.Sql
import groovy.xml.StreamingMarkupBuilder

def sql = Sql.newInstance("jdbc:jtds:sqlserver://fakedbserver:1433/mydbname", "myusername", "mypassword", "net.sourceforge.jtds.jdbc.Driver")

def xml = new StreamingMarkupBuilder().bind {
mkp.xmlDeclaration()

events{
mkp.yield "\n"
sql.eachRow("SELECT e.id as eventId, scheduled_date, event_date, league, location, tv_station, neutral_location, preseason, tba, event_type, t.team as teamId, t.number as teamRotationNumber, p.number as propRotationNumber, prop.name as propValue FROM event e left join team_event t on t.event = e.id left join proposition_event p on p.event = e.id left join proposition prop on p.proposition = prop.id where e.id <> 0 order by e.id, t.number, p.number"){
event( eventId:"${it.eventId}",
type:"${it.event_type}",
scheduledDate:"${it.scheduled_date}",
actualDate:"${it.event_date}",
leagueId:"${it.league}",
locationId:"${it.location}",
tvStationId:"${it.tv_station}",
neutralLocation:"${it.neutral_location}",
preseason:"${it.preseason}",
tba:"${it.tba}",
rotationNumber:"${it.teamRotationNumber?:it.propRotationNumber}",
teamId:"${it.teamId?:''}",
propValue:"${it.propValue?:''}"
)
mkp.yield "\n"
}
}
mkp.yield "\n"
}
new File("scheduledump.xml").write(xml.toString())
println xml


30ish lines of code and most of that is creating the element/values? (Oh, and I don't really know Groovy that well yet) Anyone want to attempt that in Java?

it's the little things...

sigh. I found myself making a modification to a legacy Java app the other day and I wanted to use a switch instead of this convoluted if/elseif/else mess that was in the code. I drew a blank... WHY couldn't I remember how to do ranges in a Java switch statement?!

Something like Ruby has... (and this is simplified considerably)

tempF = 60
result = case score
when 0..32: "Frozen"
when 33..40: "Way too cold for me"
when 41..55: "Too cold for me"
when 56..82: "Brrrr..."
when 83..110 "Now we're talking"
else "Time to move"
end
puts result
Oh, that's right... Java doesn't DO ranges (gotta love it's C++ roots)

Tuesday, December 2, 2008

Wrapping pre tags

Ok, here's a quickie... my previous post had the problem of long code lines. I.e. the code was in a <pre> tag but most of it was getting cut off since the column was too narrow.

Found this after a couple mins of searching...
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap !important;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}

Completely ignoring DTD with SAXBuilder/JDOM

I recently worked on a project where we were sent a large number of XML documents, all bearing a SYSTEM doctype. The source had provided a somewhat large zip file of of XML DTDs for those documents, all organized into subfolders.

Not horrible, BUT they were obviously a Windows shop because there was no consistency with the dtd location filenames and they didn't necessarily match the case of the provided dtd files.

As an example:
<!DOCTYPE MLB_SCORING_UPDATE SYSTEM "xmldtds/Major League Baseball/MLB_SCORING_UPDATE.dtd">
To make matters more annoying, they weren't even consistent with the main directory "xmldtds" here, "Xmldtds" there... fine if you're on Windows, not so great for a case-sensitive filesystem.

Sure, I could have written a script to down-case all the files in the directory structure AND captured the xml string before I transformed it into a document and downcased the dtd path through a regex/replace... but that's a lot of kludging for something I don't really care about... I'm not validating the document, I just care that it's well-formed.

First thought, this should be easy, I'll just tell it not to validate:

SAXBuilder builder = new SAXBuilder(false);
builder.setValidation(false);
Oops, actually that doesn't work... it still tries to find the DTD (and throws an exception since that filepath doesn't exist on my system).

Ok, second thought - there's an EntityResolver interface, that should be helpful... I can just grab the systemId when it hits my overridden resolveEntity() method and handle it there...
package org.xml.sax;
public interface EntityResolver {
public InputSource resolveEntity(String publicID, String systemID)
throws SAXException;
}
Only problem, that doesn't seem to work. It tries to resolve the SYSTEM dtd (and blows up with an exception) before it hits my overridden method.

Finally, after a bunch of searching and wading through many posts where other people also wanted to just ignore the DTDs, I finally chanced upon a solution. You need to explicitly set the features on the SAXBuilder.

private Document parseXmlDocumentFromString(String input) throws JDOMException, IOException {
SAXBuilder builder = new SAXBuilder(false);
builder.setValidation(false);
builder.setFeature("http://xml.org/sax/features/validation", false);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
builder.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
return builder.build(new StringReader(input));
}

Hope this saves someone else some time.

welcome

fp! Ok, I'm the only one posting, so that's no big accomplishment. This blog will help me transfer some of the info I've got queued up in my head.