duminică, 21 februarie 2010

Read a CSV file in Clojure and save it in DB


I discovered that a simple program that reads a csv file and save it in a database is shorter in Clojure than in Java. I searched on google and on clojure apis to find out how can be done and this is my first Clojure useful project. This is how I've done it:

1. I used Oracle XE database, I created a user called clojuretest/clojurtest@XE and created a simple table country like this:


CREATE TABLE country (
country NVARCHAR2(20) NULL,
isocode NVARCHAR2(10) NULL
)
/

2. I installed Netbeans 6.8 with Enclojure plugin. I created a Clojure project and opened the REPL.

3. First I wanted to parse the csv file containing pairs of country and isocode without all the Java hassle.
I discovered that in Clojure is a special package for parsing stuff so I had to load in my REPL:

(use '(clojure.contrib duck-streams str-utils))
So after some googling around this is what I got:

(doseq [line (read-lines "D:\\clojure_test\\country.csv")]
(let [[x y ] (re-split #"," line)]
;(println line)
;(println x)
;(println y)
(println [x y ])

)
)
This means that each line of the country.csv is read by read-lines function and the vector [x y] will be populated with each value from csv columns.
So x will have a Afghanistan and y will have AFG.
And after each assignment I am printing the vector to see what we got.

4. Then I did some research of how to save it in the db.
For database stuff we need this package:

(use 'clojure.contrib.sql)

Then we need to declare our db connection:

(def db {:classname "oracle.jdbc.driver.OracleDriver" ; must be in classpath
:subprotocol "oracle:thin"
:subname "@localhost:1521"
; Any additional keys are passed to the driver
; as driver-specific properties.
:user "clojuretest"
:password "clojuretest" })

We need to define a insert function knowing the table name and column names of course:

(defn insert-db-entry
"Insert data into the table"
[country,isocode]
(clojure.contrib.sql/insert-values
:country
[:country :isocode]
[country isocode]))

5. We define a test function to see if It works:

(clojure.contrib.sql/with-connection
db
(clojure.contrib.sql/transaction
(insert-db-entry "Albania" "ALB") ))

If was ok will get a (-2) response in the REPL other wise an exception will occurr.
Actually this was all the hard work because for a strange reason clojure did not see my jdbc jars (ojdbc14.jar) even if they were in classpath.
So I added as libs in Netbeans project and restarted the IDE and it worked.

6. We actually write the code to do the inserts from the csv file in the db.
Note that I do a dummy insert , no ckecking, just to see that works.

(clojure.contrib.sql/with-connection
db
(clojure.contrib.sql/transaction
(doseq [line (read-lines "E:\\clojure_test\\country.csv")]
(let [[x y ] (re-split #"," line)]
(insert-db-entry x y)
)
)))

So instead of printlin the vector I could actually insert in db the x and y values!
It worked! Maybe now it's time to search how to do filters on the data...but next time.

vineri, 19 februarie 2010

A useful networking tool GNS3


In my searches I discovered a useful tool for networking guys.

From their website I find what it is:
"GNS3 is a graphical network simulator that allows simulation of complex networks"

So I tried to see what it does. See my screenshot.


Teamviewer works with MacOSX


Teamviewer works out of the box with MacOSX 10.5.7.
Boot in safe mode with -x is not required. See my screenshot,
is worth a thousand words...

How to remove vowels from a string

It seems that's easy in Java 5 using regex. Have a look on this code:
Pretty straightforward.

public class NoVowels
{
public String replaceVowels(String source)
{
String result="";
String regex="[AEIOU]";
String replacement="";
result=source.toUpperCase().replaceAll(regex,replacement);
return result;
}

public static void main(String[] args)
{
String test = "Abracadabra";
String result = "";
NoVowels nw = new NoVowels();
result = nw.replaceVowels(test);

System.out.println("test string="+test);
System.out.println("result string="+result);
}
}

And we obtain:
test string=Abracadabra
result string=BRCDBR

Now I'll try same thing in Clojure.
I have found and installed clojure box.
I go on my windows xp in start->programs->clojure box->clojure box link.

In the repl I type:

(require '(clojure.contrib [str-utils2 :as s]))

I did this to select the namespace for this replace function which in this example is s. Then I write the replace code.

(s/replace (s/upper-case "Abracadabra") #"[AEIOU]" "")

And I get:
"BRCDBR"

Two lines of code !


Hello WWWorld

Hello World!
I found you first!