Search

August 30, 2012

Using ANT Hibernate Tools with Hibernate 4

Recently I have been upgrading a JEE application to the latest versions of the libraries used. In particular I was upgrading from Hibernate 3 to Hibernate 4.

In this particular application, we maintained Hibernate mapping files and used Hibernate Tools to generate the schema via an ANT task. At first glance, it seemed that Hibernate Tools had been completely absorbed into JBoss Tools for Eclipse. It also appeared that Hibernate Tools did not support Hibernate 4. However, it turned out I was able to get what I needed.

So the first trick was locating Hibernate Tools. From the download page for JBoss Tools (http://www.jboss.org/tools/download/), drill into the download link at the bottom for the version of JBoss Core Tools you want. In my case the latest was 3.3. On this page you will find separate downloads for JBoss Tools and Hibernate Tools. I downloaded the zip for Hibernate Tools.

From here you will find that the download consists of plugins for Eclipse. But if we tear apart the right one we can get to the hibernate-tools.jar file needed for the ANT task. In this case the right jar was plugins/org.jboss.tools.hibernate4_0_3.5.1.v20120715-0252-H98-Final.jar.

After exploding the jar I found the hibernate-tools.jar in the lib/tools subdirectory. Unfortunately my fun was not over. I soon ran into this problem:

java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

I needed to include the jars from the lib/required directory as well. But we were still not quite there:

[hibernatetool] SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
[hibernatetool] SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

BUILD FAILED
c:\eng\projects\sc\build.xml:83: java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder

Luckily the error message at the indicated URL was informative. I downloaded a implementation of slf4j and included the slf4f-nop.jar in the classpath. (Note that using the slf4j-log4j jar from the lib directory caused all the useful output from the hibernatetool ANT task to be suppressed. And I did not want to set up a log4j configuration just for this. Have I mentioned how frustrating all these logging frameworks are?)

As a bonus, here’s one more issue I encountered while upgrading Hibernate Tools:

org.hibernate.MappingException: Could not determine type for: org.jasypt.hibernate4.type.EncryptedStringType

Hibernate Tools was having issues with the properties configured to be encrypted via jasypt. (An excellent way to include encrypted data into a database transparently, by the way.) The trick turned out to be to define the sql-type attribute on the column element under property element in the mapping file.

In case you were wondering, I was able to get Hibernate Tools to generate POJOs, documentation and mapping files. I’m not using anything specific to Hibernate 4 so I don’t know if I can declare Hibernate Tools completely compatible with it, but it seems a great deal of functionality is available, if you work a little.

August 6, 2012

Ruby Play List Copier, Take 2

I finally got back to my little Ruby project over the weekend. The idea was to write a tool to copy an m3u play list and associated files to my mp3 player since Rhythmbox and Banshee were not up to the task. I used the ruby-taglib library from http://robinst.github.com/taglib-ruby/ to access mp3 tags.

My first attempt was turning out a little too much like an enterprisey Java project so I decided to back up and try to make it a little lighter and more Ruby-esque. I decided on a module for parsing play lists would allow for the best re-use for that functionality while simple classes would represent play lists and play list entries. With the library written the main script became the following:

#!/usr/bin/env ruby
#
require 'fileutils'
require './playlist-parser'

dest_dir = File::expand_path(ARGV[0])
source = PlayList.new(ARGV[1])
dest = PlayList.new(File::join(dest_dir, File::basename(source.to_s)))

source.read_playlist do |entry|
  basename = PlayListEntry::sanitize(entry.artist + ' - ' + entry.album +
    ' - ' + entry.track + ' - ' + entry.title + '.mp3')
  dest_entry = PlayListEntry.new(basename)
  dest.playlist_entries << dest_entry
  dest_file = File::join(dest_dir, dest_entry.to_s)
  if not File::exists?(dest_file) then
    puts "#{entry.source} => #{dest_file}"
    FileUtils.copy_file(entry.source, dest_file)
  else
    puts "#{dest_file} exists"
  end
end

dest.write_playlist

This script is pretty simple. It opens the given play list and iterates over the entries, creating a new play list based on the passed destination directory. The file is copied over as Rhythmbox and Banshee do, using the tag information to determine the file name. Then when we are done we write out the new play list.

The library file is little longer. It includes a module named PlayListParser which had the parsing functionality (such as it is, a play list file is not really very complicated; if you are reading this far open one up in a text editor and you’ll figure it out no problem). Then we have the PlayList class which includes the parser module and provides a write_playlist method. Finally the PlayListEntry which makes tag access convenient.

# http://robinst.github.com/taglib-ruby/
require 'taglib'

module PlayListParser

  attr_accessor :playlist, :playlist_entries

  def parse_playlist(playlist, &block)
    @playlist = playlist
    @playlist_entries = []
    save_dir = Dir::pwd
    Dir::chdir(File::dirname(playlist))
    File.open(playlist) do |file|
      file.readlines.each do |line|
        line = line.strip
        if line.empty? or line[0] == '#' then
          next
        end
        if not File.exists?(line) then
          puts "WARN: File #{line} does not exist in play list #{@playlist}"
        end
        entry =  PlayListEntry.new(line)
        @playlist_entries << entry
        block.call(entry) unless block == nil
      end
    end
    Dir::chdir(save_dir)
  end

end

class PlayList

  include PlayListParser

  def initialize(playlist)
    @playlist = playlist
    @playlist_entries = []
  end

  def read_playlist(&block)
    parse_playlist(playlist, &block)
  end

  def write_playlist
    File::open(playlist, 'w') do |file|
      file.puts('#EXTM3U')
      file.puts(@playlist_entries)
    end
  end

  def to_s
    return @playlist.to_s
  end
end

class PlayListEntry

  def self.pad_track(track)
    return ( track < 10 ? '0' + track.to_s : track.to_s)
  end

  def self.sanitize(source)
    return source.gsub(/[":\?]/, '_')
  end

  attr_accessor :source, :album, :artist, :comment, :genre, :title, :track, :year

  def initialize(source)
    @source = source
    read_tags
  end

  def read_tags
    if File.exists?(source) then
      TagLib::FileRef.open(source) do |fileref|
        tag = fileref.tag
        @album = tag.album
        @artist = tag.artist
        @comment = tag.comment
        @genre = tag.genre
        @title = tag.title
        @track = PlayListEntry::pad_track(tag.track)
        @year = tag.year unless tag.year == 0
      end
    end
  end

  def to_s
    return @source.to_s
  end
end

One drawback of the parser is the use of the current working directory to handle relative paths in the play list file. This construct makes the parse_playlist method not thread-safe. (I can’t help but think about these things after working on servers; but I left it that way since this is supposed to be a simple script.)

In the end I learned a few useful things along the way, like the difference between sub and gsub as well as some of the characters that are escaped by Rhythmbox and Banshee when making file names. Also how to split up a Ruby project into more than one file. And I ended up with something I can actually use. All in all a successful excursion into Ruby.

August 2, 2012

Ruby Play List Copier, Take 1

So I finally got back to my Ruby play list project. The next mini-goal would be to parse a play list file and print out the converted file names. I created a PlayListEntry class and a PlayList class and things were moving along very well:

require 'taglib'

class PlayListEntry

  SEPARATOR = " - "
  SUFFIX = ".mp3"

  attr_accessor :source, :dest, :dest_dir

  def initialize(source)
    @source = source
    determine_dest
  end

  def set_dest_dir(dest_dir)
    @dest_dir = dest_dir
  end

  def determine_dest
    TagLib::FileRef.open(@source) do |fileref|
      tag = fileref.tag
      if not tag then
        puts "No tags for #{source}"
        next
      end
      basename = tag.artist + SEPARATOR + tag.album + SEPARATOR +
        tag.track.to_s + SEPARATOR + tag.title + SUFFIX
      if dest_dir then
        @dest = File.join(dest_dir, basename)
      else
        @dest = basename
      end
    end
  end

end

class PlayList

  attr_accessor :playlist, :entries

  def initialize(playlist)
    @playlist = playlist
    read_playlist
  end

  def read_playlist
    @entries = []

    File.open(playlist) do |file|
      file.readlines.each do |line|
        line = line.strip
        if line.empty? or line[0] == '#' then
          next
        end
        if File.exists?(line) then
          @entries << PlayListEntry.new(line)
        else
          puts "File #{line} does not exist"
        end
      end
    end

  end

end

playlist = PlayList.new(ARGV[0])
playlist.entries.each {|x| puts x.dest }

That’s when I realized I am pretty much just doing Java style code in Ruby. I need to change this up and try to make it more Ruby-like. Possibilities include using modules or code blocks. We’ll see where it goes.