Wednesday, May 21, 2008

Mapping a document from byte[] to BLOB in Grails on Oracle

For CDR (http://code.google.com/p/configuration-data-repository/) I had to upload a document of any sort into an oracle database. Using a byte[] type worked just fine with the embedded HSQL database but when I deployed it to Oracle 9i or 11g (that's our platforms) it failed horribly. This was apparently due to hibernate creating in Oracle a 'RAW' object with a maximum size of 255. I'm not an Oracle DBA so I don't know if that is appropriate but it wasn't working.

My second thought was to change the object type in my domain object to blob:

static mapping = {
document type: 'blob'
}


But that didn't work either because it couldn't automatically convert a byte[] to a BLOB. I was able to find others who had had similar issues on the Grails nabble and a blog posting by a gentleman named Ryan using hibernate to convert byte[] to BLOB were old (by Grails standards) and I wanted to see if Grails could handle this using the new ORM DSL instead of hibernate mapping files. This is what I came up with:


import java.sql.Blob
import java.sql.SQLException
import org.hibernate.Hibernate

class Documentation extends ConfigurationItem {
int docVersion
byte[] document
Blob documentBlob
String fileType
String fileName
String fileSize
String title
String abstraction
DocumentationType documentationType

Date dateCreated
Date lastUpdated

static transients = ["document"]
static belongsTo = DocumentationType
static constraints = {
docVersion(nullable: true)
document(nullable: true)
documentBlob(nullable: true)
fileType(nullable: true)
fileName(nullable: true)
fileSize(nullable: true)
title(nullable: true)
abstraction(nullable: true)
documentationType(nullable: true)
}

static mapping = {
documentBlob type: 'blob'
}

def getDocument() {
if (documentBlob == null)
return null;
return toByteArray(getDocumentBlob());
}

def setDocument(document) {
setDocumentBlob(Hibernate.createBlob(document));
}

boolean equals(obj) {
if (this == obj) return true;
if (!obj || obj.class != this.class) return false;
return id?.equals(obj.id)
}

int hashCode() {
return id ? id.hashCode() : super.hashCode()
}

private byte[] toByteArray(Blob fromBlob) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
return toByteArrayImpl(fromBlob, baos);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) {
}
}
}
}

private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos) {
byte[] buf = new byte[4000];
InputStream is = fromBlob.getBinaryStream();
try {
while (true) {
int dataSize = is.read(buf);

if (dataSize == -1)
break;
baos.write(buf, 0, dataSize);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {
throw ex;
}
}
}
return baos.toByteArray();
}

String toString() {
return "${name}"
}
}

Notice all I had to do was create an ORM mapping for documentBlob. So far so good! It seems to be working in our testing in both HSQL and Oracle 9i. Has anyone else ran into this issue?

Thursday, May 8, 2008

Notes from the Groovy and Grails meetup

I went to the Groovy and Grails meetup which was basically the highlight of CommunityOne, although it wasn't technically part of communityOne. It was put on by No Fluff Just Stuff and G2One.

It started with Guilluime giving the state of the Union on Groovy and Grails. Then came folks from LinkedIn talking about their experiences using Grails and finally by Mathew Porter of Contegix talking about why they use Grails internally instead of Rails as they do a tremendous
amount of Rails hosting. This was very interesting and he made two big points.
  1. Grails scales for less cost (hardware)
  2. The Grails platform is more stable and they don't have to constantly upgrade the technologies, re-train developers, etc.

After the presentations they formed a panel of No Fluff Just Stuff experts and talked about subjects like the future of Java, where languages fit with the platform, SOA, etc. It was a lively discussion and interesting to see the experts contemplating the same issues that the rest of us humble developers have.

It was nice to meet and talk to folks there. I met Dave Klein JUG leader (from where evades me), Jeff Brown and Guillaume Laforge of G2One fame, Dierk Konig , writer of the fantastic Groovy In Action (GINA) and my beloved Webtest plugin for Grails, and my favorite Tech writer Scott Davis who is also the Chief Editor of aboutgroovy.com (correction, I had before stated that Scott Davis was the CE of groovyblogs.org which is Glen Smith). All very cool people to talk too and very passionate about groovy and grails.

Tuesday, May 6, 2008

JavaOne: Day 1 (Tuesday): Keynote

Knowledge Dump:
  • Java is on 3 Billion Devices(mostly phones)
  • Card scanners, blah blah blah, old news
  • John Gage just made a joke (sorta) about not having a social security card with an electronic identifier, or as he said:
    "Hi, I'm an American, please detonate the closest device."
  • CO2 sensor, used for mining, etc. Can be used for monitoring water usage, power usage, unsafe gas levels such as CO2 etc.]
  • Gas meater can monitor 40 different times of gas
  • Amazon Kindle (little electronic book) done in Java
  • Very cool mash-up Demo of a multi-media app done in JavaFX on applet, desktop, and mobile
  • one thing was cool is that they were able to drag the applet to the desktop and drag photos from the desktop to the application, it felt very integrated
  • They were having ridiculous network issues, then again so am I
  • Very cool 3D high-def stuff, very fast, very cool looking stuff
  • Java 6 update 10 preview release
  • JavaFX Desktop SDK EAP (July)
  • JavaFX Desktop 1.0 (Fall)
  • JavaFX Mobile and TV (Spring 2009)
  • Glassfish V3 Kernal
    • 98KB
    • Modular Design
    • Okay I'm a glassfish fanboy
  • 48,000,000 JRE downloads a month
  • Project Hydrazine
    • Find
    • Merge
    • Deploy
    • Share
    • Monetize
  • Project Insight
    • JavaFX platform will have "Instrumentation", the ability to monitor data of users and passing data to users.
    • I don't really understand what that means.
  • Holy Crap, Neil Young is up on stage
    • He's talking about how the Blue Ray sound is so much superior to anything prior
    • He's wearing shades, what the...
    • That was very cool suff, best Blue Ray Demo Ever

Wednesday, April 23, 2008

Deploying Grails and Hudson on OracleAS 10g R3

I recently had to deploy Hudson (the open-source continuous integration server) and CDR (a Grails application I built using Grails 1.0.1) at a client site onto OC4J 10g R3. As many of you old timey Grails developers may know Oracle is documented as having class loading issues with Grails applications. These issues are captured in an Oracle article written back in 2006. The fix, as documented by this article, is to set the deployment plan to "Search local classes first".

Ironically, my Grails application would not load with these settings. So I tried loading it without changing the deployment plan and Viola! It loaded with no issues.

The article did go to some good use, however. Hudson would not load without changing the setting to "Search local classes first."

Be warned, the current configuration UI is not identical to the one in the article.

Tuesday, April 22, 2008

Creating multiple Jetty Server instances

For my current project I was required to create multiple Jetty Server instances to run different applications and I found the documentation to be lacking.
It's possible that someone documented this somewhere but I couldn't find much info using the normal channels (google searches, etc).
I'm very hopeful that this will start some conversation and people will let me know if there are better ways to do this.

We're running Jetty on a Solaris 10 instance which I access using SSH. The requirements I had were:

  1. Jetty had to run in a shell-less mode. Meaning that when I logged out the server didn't shut down.

  2. I needed multiple instances of the Server to run different applications.
    It wasn't required for them to run in seperate JVMs which frankly I have yet to try.

Running Jetty shell-less is as simple as using the jetty.sh start script. This is probably obvious to old-time Jetty
users but it took me some researching to find this out. Starting Jetty this way requires you to be in the $JETTY_HOME directory and sexecute the script as follows:

./bin/jetty.sh start

This is a fairly useful script and you can view other useful commands by typing:

./bin/jetty.sh

...which will spit out all the usable commands.

Well that was easy enough, so how about starting multiple instances? Jetty uses the jetty.xml file (sometimes refered to generically as config.xml) found in the $JETTY_HOME/etc directory as the default configuration file for the server. You can override the default and pass in multiple files from the command line just by typing their path after the start command:

./bin/jetty.sh start $JETTY_HOME/env/foo.xml $JETTY_HOME/env/bar.xml

What will Jetty do with two configuration files? Well there is line very early in each config.xml file that identifies the server instance:
If the id for each file is the same then Jetty will combine both files. If they are different then Jetty creates multiple instances.

So I created a new file called jetty-cdr-instance.xml by copying the jetty.xml file. The first thing I did was change the line above:

After that all you have to do is look through the file and change ports or whatever other setting you need or want to change. I changed the port from 8080 to 8081 and changed all the other ports (not sure if I needed to):

<call name="addConnector">
<arg>
<new class="org.mortbay.jetty.nio.SelectChannelConnector">
<set name="port"><systemproperty name="jetty.port" default="8081"></systemproperty>
<set name="maxIdleTime">30000</set>
<set name="Acceptors">2</set>
<set name="statsOn">false</set>
<set name="confidentialPort">9453</set>
<set name="lowResourcesConnections">5000</set>
<set name="lowResourcesMaxIdleTime">5000</set>
</set>
</new>
</arg></call>

There are a number of other settings that can be configured but one that is important is where to find deployment archives (WAR files). By default Jetty looks into the $JETTY_HOME/webapps directory, which is fine for the default instance. But for my second instance I want to deploy different apps so I created a webapps2 directory and changed the configuration setting:

<call name="addLifeCycle">
<arg>
<new class="org.mortbay.jetty.deployer.WebAppDeployer">
<set name="contexts"><ref id="Contexts"></ref>
<set name="webAppDir"><systemproperty name="jetty.home" default=".">/webapps2</systemproperty>
<set name="parentLoaderPriority">false</set>
<set name="extract">true</set>
<set name="allowDuplicates">false</set>
<set name="defaultsDescriptor"><systemproperty name="jetty.home" default=".">/etc/webdefault.xml</systemproperty>
</set>
</set>
</set></new></arg></call>


And that's about it! So now if I feed both files at the command line I get two server instances, one running on the default port 8080 and the other 8081 and each running the applications in their respective webAppDir directory. But what if I don't want to pass the file names in the command line?

I'm sure there is a better way to do this, probably involving the jetty.conf file, but I was unable to find sufficient documentation. In the jetty.sh script you will find the lines:

#####################################################
# Run the standard server if there's nothing else to run
#####################################################
if [ -z "$CONFIGS" ]
then
CONFIGS="${JETTY_HOME}/etc/jetty.xml"
fi

I changed:

CONFIGS="${JETTY_HOME}/etc/jetty.xml"

to:

CONFIGS="${JETTY_HOME}/etc/jetty.xml ${JETTY_HOME}/etc/jetty-cdr-instance.xml"

and now by simply typing:

./bin/jetty.sh

I get both instances running.

And that's it! I'm still pretty new to administering Jetty so if you know better ways to handle these things please let me know.

Monkey Search