Tuesday, December 22, 2009

A Basic Ant+Ivy+Scala Setup

I've decided that for my latest project I'd give Ant with Ivy a go as my build system. To start with, I'm going to try for the simplest possible setup necessary in order to compile my project (so at this stage, it's not even rolling the output up into a jar - I can fix that later). At it's most basic level, this means that I'll need two XML files to get everything to build:

ivy.xml

ivy.xml contains information about the dependencies needed to build the project. To compile scala source, I'll need to add two dependencies - scala-library and scala-compiler.

<ivy-module version="2.0">
<info organisation="com.maethorechannen" module="snow-core"/>
<dependencies>
<dependency org="org.scala-lang" name="scala-library" rev="2.7.7"/>
<dependency org="org.scala-lang" name="scala-compiler" rev="2.7.7"/>
<!-- other dependecies -->
</dependencies>
</ivy-module>


If you've used Maven then this will look vaguely familiar yet more compact - groupId becomes org, artifactId becomes name and version becomes rev. As by default Ivy uses Maven's repositories, you can use the same values as you would in Maven.

build.xml

My build.xml will need to do 3 things:

  1. download ivy

  2. setup scala

  3. compile



Strictly speaking, the first item is not technically required if I manually install Ivy into Ant. For the moment, it seems easier if I just set it up so that Ivy gets automagically installed if need be. Fortunatly, the ivy-go example build.xml file shows us how to do this.

The Scala side of things is also fairly straightforward. The scala-lang.org page on Scala Ant Tasks gave me a fairly good idea of what needed to be done, however I had to make a few changes:

  • make the init target depend on the install-ivy target

  • modify init so that it executes ivy:retrieve (which downloads the dependencies) and modify the way init generates the build classpath so that it includes jars from the lib directory

  • modify the taskdef that imports the scala tasks (also in the init target) so that it finds scala-compiler and scala-library in the lib directory and not in scala.home

  • modify the build target, so that it compiles all scala source files in the src/main/scala directory and subdirectories



As the build.xml file is a bit big for a blog post, you can find it here

Friday, December 18, 2009

Accessing BBC Listen Again data with YQL

The BBC have had for a while now XML feeds detailing their "Listen Again" content. For some reason, today I decided it would be fun to access that data from YQL.

The quickest way is to just use

select * from xml where url='http://www.bbc.co.uk/radio/aod/availability/radio4.xml'


However, I wanted to try out Open Data Tables, and this seemed like a good a time as any. Describing an Open Data Table is surprisingly easy. It's just an XML file, with some metadata about the table and then some binding information that tells YQL where to get the repeating data from.


<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd">
<meta>
<author>Scot McSweeney-Roberts</author>
<documentationURL>http://froth-and-java.blogspot.com/accessing-bbc-listen-again-data-with-yql</documentationURL>
<sampleQuery>select entry from {table} where station="radio4" and entry.parents.parent.pid="b006qfvv"</sampleQuery>
</meta>
<bindings>
<select itemPath="schedule.entry" produces="XML">
<urls>
<url env="all">http://www.bbc.co.uk/radio/aod/availability/{station}.xml</url>
</urls>
<inputs>
<key id="station" type="xs:string" paramType="path" default="radio4" />
</inputs>
</select>
</bindings>
</table>



You'll have noticed the "station" key - the BBC has a separate feed for each service, so Radio 1's feed is at radio1.xml, Radio 4's is at radio4.xml, Radio Scotland is at radioscotland.xml, etc. By using a key and inserting its value into the select URL I can use a single Open Data Table definition and access whichever feed I want. The reason why I called it station and not service is that service is a child element of each entry element, so to keep things simple I called the key "station".

One reason for using an Open Data Table is that makes it slightly easier to query - for example, a query to select all Shipping Forecasts on Radio 4 without using an Open Data Table is


select * from xml where url="http://www.bbc.co.uk/radio/aod/availability/radio4.xml" and itemPath="schedule.entry" and parents.parent.pid="b006qfvv"


With an Open Data Table, it's


USE "http://sites.google.com/site/frothandjava/home/code/bbc_aod_open_table.xml"AS aod;
SELECT * FROM aod where station="radio4" and parents.parent.pid="b006qfvv"


(It's not really much of a difference though - I think table definitions come into their own when you use them to insert data in to a web service)

One of the more useful elements in the feed are the "mediaselector" links. A mediaselector link is a link to yet another XML file, but this file contains links to the available media for a particular programme. Some of the links aren't particularly useful, as they're internal iPlayer links, but some are useful as they're the links to WMA and Real Audio streams (though the BBC are dropping support for Real Audio at some point in the future).

Again, as it's XML it's easy to access from YQL

select * from xml where url='http://www.bbc.co.uk/mediaselector/4/mtis/stream/b00p6w2c'

(note, that query will probably not work after lunchtime on the 19th December, 2009 as that particular episode falls out of it's listen again window)

However, there is a bit of a problem at the moment for UK users of this data while accessing it through YQL - the BBC are currently sending a slightly different mediaselector file depending on where the request came from. As Yahoo's YQL servers are located outside the UK, we get the "international" version of the file and not the one containing UK data. Not only does this mean that we can't get access to the higher quality UK only versions of the streams, but I've noticed that the international WMA streams don't seem to be working in the UK (but the RA ones do). Apparently, this will be solved "at some point in the new year".