Friday, December 25, 2009

Transcoding Videos Using VLC

I found this great how-to for using VLC to converter/shrink/transcode videos. This is so you can shrink them to play on your ipod, iphone, Android device, whatever.

Its a bit slow as I think it actually plays the file normally as it saves the output file. Regardless, It was simple and I got it working on my Mac although the preferences menu entry is in a different spot (under the VLC menu entry ).

Tuesday, December 22, 2009

Easy Hex SHA-1/MD5 Hashes with Groovy

The Java API has included support for a number of cryptographic hash functions ( MD5, SHA-1, etc) since Java 1.4 via the java.security.MessageDigest class. If you ever tried to use these in a web-centric context you've probably been a bit annoyed by the fact that it only provides hash results as byte arrays. Here's a quick and easy solution using Groovy that I thought I'd share:


def messageDigest = MessageDigest.getInstance("SHA1")
messageDigest.update( stringToHash.getBytes() );
def sha1Hex = new BigInteger(1, messageDigest.digest()).toString(16).padLeft( 40, '0' )


Notice the padding of zeros since the length of the SHA-1 hex needs to be 40 characters. If you're using a different hashing hex string length will change.

Note: Code updated to reflect an improvement submitted in the comments.

Labels:

Wednesday, December 16, 2009

Production Groovy Part I: The trouble with Grape

Like Perl, Groovy's utility is most evident while leveraging the work of others. In Groovy 1.7, Grape makes doing so intuitive with the addition of annotations on import statements:



@Grab( group = 'com.sun.jersey', module='jersey-core', version = '1.1.2-ea' )
import com.sun.jersey.api.core.DefaultResourceConfig
@Grab( group = 'com.sun.jersey', module='jersey-server', version = '1.1.2-ea' )
import com.sun.jersey.api.container.httpserver.HttpServerFactory



The trouble with Grape is that by default it resolves dependencies by contacting or attempting to contact certain Maven2 repositories. Now, this isn't a problem if you're a web startup looking to bring a product to market as quickly and cheaply as possible. But it is a problem if you're looking to start deploying Groovy to a secure production environment. Fortunately, Groovy's close coupling with Java provides a clean and elegant solution.

The key is that Maven2 remote repository caching and local repository hosting has been made easy by Artifactory. It can be configured to dynamically dial out and cache artifacts on demand from remote repositories. It can also more simply be used to manually manage artifact deployment. Thus provinding both flexibility and control.

In order to take advantage of Artifactory you'll want to modify the default Grape/Ivy configuration so it points to your internal Artifactory repository by default. The bad news is that you'll need to modify the an xml file and rebuild the the jar. The good news is that the groovy source itself uses Ivy so modifying the xml and building Groovy is really easy.

Simply download the latest Groovy source zip. Then modify '/src/main/groovy/grape/defaultGrapeConfig.xml'. You can then build yourselve a new zip distribution by running 'ant createJars -DskipTests=true'.
Skipping the tests is optional, of course.

Thats it. Once you explore Artifactory a bit you'll discover that it can provide as little or as much control of the artifacts available to Grape as you desire.

Labels: , , ,

Friday, December 11, 2009

Fido iPhone Roaming Fraud

Here's an interesting post which underscores why Canadians need more wireless broadband competition. Click on the lick to read about how Fido's data roaming screws over a customer.

Wednesday, December 2, 2009

Groovy Serialization - Part 2 - Objects

In my previous post I discussed the serialization of simple Groovy data structures. Arbitrary objects can also be serialized using ConfigObject and ConfigSluper and a little trickery. The fact Groovy config files may also contain code makes this all possible.

In order to instantiate objects inside a Groovy config file, you need import the referenced objects. You also need to override the toString to create the proper instantiation string.


package MyPackage
class MyObject {
def data;
String toString() {
def serializedString = "new MyObject( data : '${data}' )"
return serializedString
}
}

//create the datastructure
def myObject = new MyObject( data: 'wtf')
def configObj = new ConfigObject()
configObj.testing = [1, 2, 3]
configObj.nested = [ objects : myObject ]

//serialize it
new File( 'newout.groovy' ).withWriter{ writer ->
writer.write( "import ${myObject.getClass().getName()}\n" )
configObj.writeTo( writer )
}


Parsing it is simple:

def config = new ConfigSlurper().parse(new File('newout.groovy').toURL())
println config


Finally one could use .metaClass to override the toString of any Java object and make it work with this serialization technique. Be careful not to shoot yourself in the foot by doing this, as other code might expect the regular toString().

Labels: ,

Tuesday, December 1, 2009

Groovy Serialization

Groovy's lists and maps provide the simple building blocks of more complex structures. Occasionally you want to serialize these complex structures to files/streams/whatever. Previously I wrote about using JSON with Groovy. While this is still my weapon of choice for this problem, another alternative would be to use the ConfigObject and the ConfigSlurper classes from the Groovy API.

Here's how you would serialize the data using this method:

//create the datastructure
def configObj = new ConfigObject()
configObj.testing = [1, 2, 3]
configObj.nested = [ objects : 'wtf' ]

//serialize it
new File( 'newout.groovy' ).withWriter{ writer ->
configObj.writeTo( writer )
}


Then when you want to parse it:

def config = new ConfigSlurper().parse(new File('newout.groovy').toURL())
println config


One disadvantage of this method is that the highest level structure must be a map, since that's what ConfigObject inherits from. The data also contains a lot of white-space formatting. Which could be a good or bad depending on the problem you're solving.

Labels: ,