Sunday 15 March 2009

next thing to learn - jpa

After much thought, I've decided to make jpa my next thing to learn (cue much confusion and heartbreak). I actually want to learn lift but I have no desire to learn lift mapper (I'm much too lazy for that right now). In any case, I hope to fool around with the toodledo api a little and learn some more scala, lift, jpa, maven and some voodoo while at it. I already have a broad (and largely vague) understanding of scala, jpa and maven so I wont go into details there except if there's wierd stuff to mention.

here's the game plan -

  • This project is nothing serious so eni.ola isn't going to get all worked up about it (I wish!)
  • I'll create the entities (and database stuff generally) to start with,
  • then I'll create a backend interface to manage the entities.
  • interface the app with toodledo (I plan to create an xml based cache or some sort)
  • Finally throw in some lift.

so let's start with the database thingy...

I set up the project as a plain scala project by installing maven and running the following from the commandline (actually I used eclipse to create a maven project here and then added the scala nature to the project but I have no aim of writing a tutorial on q4e):

mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create \
-DarchetypeGroupId=org.scala-tools.archetypes \
-DarchetypeArtifactId=scala-archetype-simple \
-DarchetypeVersion=1.1 \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=your.proj.gid -DartifactId=your-proj-id


A simple scala maven project comes configured already with support for junit4 and specs - so you can start testing right away. However, you've got to set up dependencies for eclipselink, derby and one or two other things. This is done by adding the following to the to the dependencies section of your pom.xml file...

    <dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.4.2.0</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>


And then adding the following repository to the repositories section of the pom.xml file.
<repository>
<id>EclipseLink Repo</id>
<url>http://www.eclipse.org/downloads/download.php?r=1&amp;nf=1&amp;file=/rt/eclipselink/maven.repo</url>
</repository>
We'll be using 2 classes for the entities - Tasque and Folder. A folder would contain a list of tasques (there's a one to many mapping here) and many tasque may belong to a folder (manytoone mapping). Scala makes doing stuff like this real easy. Here's the code for these two classes...

package eni.ola

import javax.persistence._

@Entity
class Tasque {
@Id @GeneratedValue{ val strategy=GenerationType.TABLE }
var id:Int = _
var description = ""
var createdOn:Long = _
@ManyToOne
var folder:Folder = _
}

@Entity
class Folder {
@Id @GeneratedValue{ val strategy=GenerationType.TABLE }
var id:Int = _
var name = ""
var description = ""
var tags = ""
var createdOn:Long = _
@OneToMany{ val mappedBy="folder", val targetEntity=classOf[Tasque] }
var tasques:java.util.List[Tasque] = new java.util.ArrayList[Tasque]()
}


The major things to note right now is that for the oneToMany annotation we set the targetEntity to the 'Tasque' class (i.e. classOf[Tasque]). I think this isn't necessary for good ole' java but thank God scala is not good ole' java. In any case, you'll notice all the other normal stuff like @Entity annotation to make the class as an entity, @Id and @GeneratedValue to make the field as the annotation's id and to say that the value of the id should be auto-generated using a TABLE. We also make use of the oneToMany and ManyToOne annotations on the Folder and Tasque classes respectively. Note that the mappedBy field of the Folder class' oneToMany (tasques field) annotation refers to 'folder' which is the name of the field for the corresponding ManyToOne annotation in the Tasque class. So basically we've created two entities... just like that...

but before we go on we need to specify the persistence mapping file

This file (persistence.xml) basically contains all the configuration data needed to get the jpa implementation (eclipselink, in our case) to work. This file is listed below

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="tasquePU">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

<class>eni.ola.Tasque</class>
<class>eni.ola.Folder</class>

<properties>
<property name="eclipselink.target-database" value="DERBY" />

<property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="eclipselink.jdbc.url" value="jdbc:derby:tasquedb;create=true" />
<property name="eclipselink.jdbc.user" value="" />
<property name="eclipselink.jdbc.password" value="" />

<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
</persistence>


The important thing to note here is that the entity classes are listed in this file along with the necessary info like location of the database, what type of dbms you'll be using, the name of the driver class, our the jpa implementation should handle ddl generation etc. You may visit the eclipselink website for more info.

Another thing that didn't work for me was where to put this persistence file. The persistence.xml should be put in the 'META-INF' folder and this folder should be on the classpath of your project so that the necessary classes can find it. The problem for me was that even though, I put this folder under the src folder, the generated 'META-INF' in the target folder didn't contain any xml file... so I had to manually copy the persistence file to the target folder after each "mvn clean" (of course you can tell that I almost never run that maven command).

the icing on the cake

As the icing on the cake (or just to make sure the program works) here's the junit test code...

package eni.ola

import org.junit.Test
import org.junit.Before
import org.junit.Assert._

import javax.persistence._

class EntityTest {
var factory:EntityManagerFactory = _

@Before
def setup() = {
factory = Persistence.createEntityManagerFactory("tasquePU")

val em = factory.createEntityManager
em.getTransaction.begin

val q = em.createQuery("select f from Folder f")
if(q.getResultList.size==0){
val f = new Folder

f.createdOn = System.currentTimeMillis
f.name = "First Folder Ever"
f.description = "This folder was created for testing purposes only"
f.tags = "test junit jpa"

em.persist(f)
}

em.getTransaction.commit
em.close
}

//change this function to return only one em per session
private def em = factory.createEntityManager

@Test
def testFolder() = {
val q = em.createQuery("select f from Folder f")
assertTrue(q.getResultList.size >= 1)
//assertTrue(false)
}
}


Yes, it is a messed-up test. I should have a scala object that inherits from the EntityTest class and that contains the factory (should is the keyword). But since I'm not cut out for hard work I've just gone with a straight forward class (terrible terrible programming I say).
The way jpa is defined, you create a factory and then create an entitymanager from the factory. The entity manager is used to manage your entities (duh) and that's it! It really is that simple until you run into issues with jar versions and other java black magic :(

In any case that's all for now folks... I'll upload the zipped file for the project when I'm feeling like it.

by the way

did you know Spurs are 2 goals up against Villa right now just beat Villa 1-2... ha ha! Kiss the Crest, Up the Arse!

Wednesday 4 March 2009

Ayo and Scala 4

Ayo is a game that played in various forms across parts of west africa. I learnt it as a kid growing up in Benin City but with a different set of rules from what the way it's played in large parts of the yoruba people. The Yorubas call it Ayo but you've probably heard of it by the more popular name of mencala. Needless to say I'm implementing the game as explained here. Find out more about the game here

This is the last installment before I switch to building a fancy interface. Today I'll go over the main class of the program - aptly called 'Game'. The game class makes use of virtually all the scala features that I've talked about so far and it is a rather long class by the standard of the other classes/objects so I'll look at it one interesting method at a time.


def start = {
val s = List(0,0)
val h = List(Set(0,1,2,3,4,5), Set(6,7,8,9,10,11))
val l = List(4,4,4,4,4,4,4,4,4,4,4,4)

move(Config(s, h, 0, l))
}


The 'start' method basically starts the ball rolling. It's the only method an external entity should ever have to call and hence it should be the only public class of the method (but what the heck). You'll notice that the method has no parameter list or even brackets (a scala feature we've mentioned in the past but didnt show an example of). Also the method calls the move method.



def move(cfg:Config):Unit = {
if(!Rules.hasHouse(cfg.getHouses)){
//print message alerting player of change of turn
move(cfg.changeTurn)
}

Board.draw(cfg.list)

println("\nPlayer "+(cfg.turn+1)+"\n"+cfg)
//get current player's choice... player can only select his own house and if it has seeds
val choice = getInput(cfg.getHouses.filter(cfg.list(_) != 0))
val (list, index) = plant(choice, cfg.list) //playout the choice

val ncfg =
if(Rules.canKeep(list(index)))
cfg.setList(list).plusStone(4).updateList(index,0)
else
cfg.setList(list)

val ocfg = houseKeeping(0, ncfg)
val pcfg = houseKeeping(1, ocfg)

if(!Rules.gameOver(pcfg.list))
move(pcfg.changeTurn)
else
println("Game Over: \n"+pcfg)
}


This 'move' method is the most important (depending on where you stand with the whole chicken before or after the egg issue). The method runs recursively until there's no move left and the game ends (if it ever really ends). First there's a check to see if the current player is in any position to make a move (that is if he has any house he can start a move from). The Board is then drawn on the screen and the user input is collected by called 'getInput' (another recursive function by the way). Once the user input is validated, the move is initiated proper by calling the 'plant' function which actually called the board class' roll function. Once the 'plant' function returns the rules are applied to see if any player can claim any seeds and then the game continues - the game attempts to switch play to the next player.

The only other function that's important at this stage is the 'housekeeping' method which is used to actually apply the rules i.e. assign users won seeds and, perhaps in the far inconceivable future, assign houses too. The fact that this method is pretty easy on the eye is one of the reeeally nice things about scala. You can create monstrousities with scala but elegant gamine (you can tell I just heard that word today) beauties.



def houseKeeping(turn:Int, cfg:Config, houses:List[Int]):Config={
//Board.draw(cfg.list)
//println(">>> "+houses)

if(houses.isEmpty)
return cfg
else{
var nConfig =
if(Rules.canKeep(cfg.list(houses.head)))
cfg.updateList(houses.head, 0).plusStone(4, turn)
else
cfg

houseKeeping(turn, nConfig, houses.tail)Mankala
}
}



On a personal note I'm somewhat completed something for once :| Seriously, this is perhaps the first thing apart from work and school that I think I've done for myself in a long time. I like it I think I'll continue. Since I'm just learning lift I dont know how much I'll be able to cook up for next week but we'll see.

Ciao!