Monday, December 14, 2009

CouchDB

CouchDB is a new kind of database. It's not a relational database, it's not objective database. CouchDB just stores documents. A document is something like java map, it has keys and values. Values can be strings, numbers, dates, lists, maps, also binary attachments. Documents are accessible by pure http, REST service, in JSON format. CouchDB is written in Erlang, so it is well scalable for many processors/cores. (At least this is what it's authors claim ;)) Let's give it a try.

Installation

On ubuntu issue:

apt-get install couchdb

During installation, couchdb user was created. Now you can run database as a background process:

sudo -i -u couchdb couchdb -b

Ok, fire up your favorite browser and open page http://localhost:5984/ You should see something like: {"couchdb":"Welcome","version":"0.10.0"}

Not very useful, is it? Try going to http://localhost:5984/_utils/ This is Futon, CouchDB admin tool. From here you can create new databases and documents and manage them.

Simple operations by Futon

Create database tryme and some document. Field _id is generated automatically, add two more fields:

firstname: "Pawel"
surname: "Stawicki"

Click "Save document". You can see that field _rev was added automatically. Every change of every document is remembered, and you can always get the old version.

Protection

So there is one document in the database, let's protect it. Go to /etc/couchdb/local.ini and edit [admins] section. Add:

admin = <admin_password>

Password will be automatically hashed after run.

If you want to enable access from any machine, change bind_address from 127.0.0.1 to 0.0.0.0

Operations by RESTful HTTP interface

CouchDB can be accessed by RESTful http interface. Curl is one nice tool for it, so install it if you don't have it already on your system:

sudo apt-get curl

Now issue:

curl http://localhost:5984

You should see known welcome message. Try

curl http://localhost:5984/tryme

and some data about tryme database should appear. We can also list all existing databases:

curl http://localhost:5984/_all_dbs

Ok, all this stuff above you can do by the browser. But you can also create documents and databases in CouchDB by REST interface. Try this:

curl -X PUT http://localhost:5984/tryme/1 -d '{ "firstname": "Leszek", "surname": "Gruchała" }'

You just created a new document. In curly braces is document in JSON format. It's id however is not long stream of characters, but just "1". Much more predictable and repeatable. UUIDs are generally better. CouchDB can generate one for you:

curl http://leonidas:5984/_uuids
It generates one id. If you need more, you can pass "count" parameter:
curl http://leonidas:5984/_uuids?count=3

So we've seen that CouchDB uses JSON as documents format, and we can do operations by HTTP. However, from now on, I'll be using Futon because it is just easier. Futon is CouchDB administration tool (http://localhost:5984/_utils).

Creating view by map/reduce

JSON is JavaScript format, and it allows to put also functions into the document. Map functions (from map/reduce) are useful to create something similar to SQL view.

Let's add another document to our database, with following fields:

firstname: "Leszek"
surname: "Kowalski"

Now choose "Temporary view" from selection box on the right. Here you can write map and reduce functions. For view, map is enough, let's leave reduce empty for now. Create function:

function(doc) {
  if (doc.firstname == 'Leszek') {
    emit(doc.firstname, doc.surname);
  }
}

It filters documents to those with firstname "Leszek" only.

So we can filter documents to only those which interest us. What about joins? Can we get some document, and relevant documents data in one query? It's also possible. Let's add addresses to those guys in database. First, we need to distinguish documents related to persons from the ones related to addresses. For that, add type field to each person, and as value enter "person". Now, we'll need their id's, so copy/paste it somewhere.

Create address as a new document, and add those fields:

type: "address"
person_id: <id_of_person>
city: "New York"

The same for two remaining persons. Put some another city there. Ok, now our map function is a little more complicated:

function(doc) {
  if (doc.type == "person") {
    emit([doc._id, 0], doc);
  } else if (doc.type == "address") {
    emit([doc.person_id, 1], doc);
  }
}

This way we have person always next to her address.

We learn another CouchDB feature here - result of map is always sorted by key. In this case key is 2-element array, in which first element is the person id, and second one is 0 in case of person, 1 in case of her address. It's not like SQL join, we don't get all the data in one document, but still it answers our needs - we have person and it's address.

If we are interested in specific person, we can add parameter to GET request. But first we need to save our view in "desing document". Click "Save As..." button, fill in design document name (e.g. "reader") and view name (e.g. "person-address") and voila.

Design documents are special documents in database for storing views. You can have different design documents e.g. for readers and for writers or administrators. In desing document you can set a lot of stuff telling CouchDB how to render it's content (means how to change it into nice html). If you want to learn more about design documents, look into CouchDB book.

GET parameters for narrowing search

Now when our view is saved, we can use GET request to get it's content, and set parameters to limit what we get to person which we are interested in. Such URL: http://localhost:5984/tryme/_design/reader/_view/person-address?startkey=["1",0]&endkey=["1",1] will return person with _id=1 and it's address documents.

Another useful parameters are:

  • key - for specific key (not range, like in case of startkey, endkey)
  • descending=true - by default view is ordered by ascending key, set this parameter to order it descending
  • group_level - sets reduce level. Default is 0.
  • group=true - behaves like group_level set to maximum
  • revs_info=true - lists revisions of specified document. Applicable only to document selected by id, not to view

To understand group_level, we'll need reduce function. First, let's add some more parameters to our persons. Let's add "position" and "salary":

To one person add:

position: "manager"
salary: 5000
To second one:
position: "developer"
salary: 3000
and to third one:
position: "developer"
salary: 3500
Now create new view, with map and reduce functions:
//map:
function(doc) {
  emit([doc.position, doc._id], doc);
}

//reduce:
function(keys, values, rereduce) {
  var salaries = 0;
  for(i = 0; i < values.length; i++) {
    salaries += values[i].salary;
  }
  return salaries;
}

Save this view as "salaries". Now open URL http://leonidas:5984/tryme/_design/bla/_view/salaries and output is:

    {"key":null,"value":11500}

All values are grouped, and key is ignored.

Add parameter: http://leonidas:5984/tryme/_design/bla/_view/salaries?group_level=1 and it returns

{"key":["developer"],"value":6500},
{"key":["manager"],"value":5000}

Values are grouped for first level of key (first element of key array).

group_level=2 returns
{"key":["developer","61fe9c6c226b978f74b76329191806b3"],"value":3000},
{"key":["developer","eb3873f48bb581df13762324b8ec0313"],"value":3500},
{"key":["manager","1"],"value":5000}

Two elements of array are taken into account. In this case, it is the same like group=true, which takes all elements of key array.

What is rereduce for?

As you noticed, reduce function has third parameter rereduce

Result of map function is kept as sorted B-tree. Let's assume we want to summarize some value from each document (tree node). Just like salaries.

First, there are keys and whole nodes (because value of our map function is whole document) passed to reduce function, and rereduce is set to false

Look at the picture, we can reduce branch of the tree into 17, another branch into 4, and third one into 2. Assume each branch has common key at specified group_level (e.g. all people from first branch are developers, second are managers and third are administrators, if group_level is set to 1).

Then reduce function is called again, with following parameters:

function(["developer", "manager", "administrator"], [17, 4, 2], true);

There is common key for whole branch, reduced scalar value for that branch, and rereduce parameter set to true.

Important thing here is to remember that not always values are whole nodes, sometimes it can be already reduced values, and in such case rereduce parameter is helpful to distinguish this situation. In fact, our reduce function wouldn't work for big amount of nodes, because it handles only nodes (only rereduce=false case), not reduced values. To work with a lot of data, we should handle also scalar values:

function(keys, values, rereduce) {
  if (rereduce) {
    return sum(values);
  } else {
    var salaries = 0;
    for(i = 0; i < values.length; i++) {
  }
}

Now it should count and sum all the salaries.

Wednesday, November 18, 2009

Mercurial installation and remote server interaction by hg-login

I want to have mercurial on my machine, but I also want to have "central repository" for continuous integration builds. I chosen mercurial because it is fast (like git), and it has good support in NetBeans (at least I heard it has ;)).
To push/pull changes to/from server, I use hg-login. Ssh is also necessary. Ok, so here are the steps:
1. Install mercurial on both client and server.
apt-get install mercurial
2. Create user mercurial on the server, and disable his shell.
sudo adduser mercurial
Edit /etc/shadow and set his password to "*".
3. Go to server (ssh will suffice) and switch to user mercurial.
sudo su - mercurial
4. Go to /home/mercurial and create repositories directory.
cd /home/mercurial
mkdir repositories
5. Create file hg-login in /home/mercurial. Copy script there. Script can be found on http://mercurial.selenic.com/wiki/HgLogin
mcedit hg-login
It can be necessary to change the script. In my case I needed to change /usr/local/bin/hg to /usr/bin/hg. Change to where your hg command is located.
6. Go back to client machine. Generate ssh keys pair for yourself.
ssh-keygen
Add private key to your ssh agent.
ssh-add
This way when you connect by ssh from client, you are automatically authenticated.
7. Go to server again. In /home/mercurial/.ssh create file authorized_keys.
cd /home/mercurial/.ssh
touch authorized_keys
In this file put line:
command="/home/mercurial/hg-login franek",no-port-forwarding,no-X11-forwarding,no-agent-forwarding [key]
franek is user name. Replace [key] with content of your .ssh/id_rsa.pub file from client. Put whole content there (with ssh-rsa in the beginning and <user>@<host> at the end).
8. Create repository in /home/mercurial/repositories/.
cd /home/mercurial/repositories
mkdir myapplication
cd myapplication
hg init
9. Allow franek to access myapplication repository. In /home/mercurial/repositories create file myapplication.allow. In this file list users who has to have access to myapplication repository. In this case franek, so the file looks like this:
franek
10. On client machine, go to directory where your application is: cd <yourdir>/myapplication
11. Create local mercurial repository.
hg init
12. Add all what is in /myapplication directory to local repository.
hg add
13. Commit added files.
hg commit
You'll need to edit commit comment.
14. Push changes to remote repository.
hg push ssh://mercurial@yourserver/myapplication
While creating this recipe, hg-login site was very helpful.
As I mentioned before, I chosen mercurial because of Netbeans. But I don't find Netbeans support of mercurial satisfactory. I am used to eclipse and it's great support for CVS. In eclipse, if there are some changes in CVS and I don't have them (incoming changes), I can see what has changed (file by file diff) before I update my code. I failed to do this in Netbeans with mercurial.

Tuesday, September 8, 2009

JAVA eXpress in English

JAVA eXpress, Polish magazine about (yes, you guessed it right) Java, from now on is accessible in English. You can get it from http://www.javaexpress.pl/
In this issue:
  • Introduction to Grails
  • Problems of large J2EE applications
  • Graphical Modelling Framework
  • J2ME: Objects Serialization
  • XML in JAVA - XStream Library
  • TeamCity: pre-tested commit
  • Express killers, part III
  • GroovyMag review - June 2009
  • Layering
Check it out and have a nice reading :)

Thursday, August 20, 2009

Google Chrome on Linux with Flash

For some time now I am using Google Chrome. I like it, because it is extremely fast. Quite a blocker for using it as a preferred browser was lack of Flash plugin. Now I have Flash thanks to author of this blog.

All you need to do:
1. Download and extract Adobe Flash player plugin for Firefox
from here. Download 32bit version, even if you are using 64bit linux.
2. Go to
/opt/google/chrome and create directory plugins.
3. Copy
libflashplayer.so to this directory
4. Run google-chrome --enable-plugins

Enjoy :)

Monday, August 10, 2009

Setting up backup by rsync

I want to backup my files on another server. So I go to another server, and create file /etc/rsyncd.conf:

secrets file = /etc/rsyncd.secrets
#Global properties
read only = yes
list = yes
#User on server
uid = backup
#User's group
gid = backup

#Protected share for backups.
[files]
comment = For your eyes only
path = /home/backup/
auth users = franek
read only = no
hosts allow = 192.168.1.64
hosts deny = *
list = yes
We are using user backup as rsync files owner. Don't forget to create him.

So now we need to create entry for franek in rsyncd.secrets:
franek:his_password
rsyncd.secrets cannot be readable for all. In such case rsync daemon will not allow access to protected shares. Set permissions to 600.

We need to do one more thing before starting the daemon. Go to /etc/default/rsync and set RSYNC_ENABLE=true

Ok, issue sudo /etc/init.d/rsync start and rsync deamon is running.

Now go to the client machine. The one we want to make backups from. I want to backup whole /home, so my command looks like this:
sudo rsync -aXAvz --delete --delete-excluded --exclude-from=$DIR/backup.excludes --password-file=$DIR/rsync-pass /home franek@moon::files
So there is sudo rsync, and then some options:
-a the same as -rlptgoD, which is:
-r recurse into directories
-l copy symlinks as symlinks
-p preserve permissions
-t preserve modification times
-g preserve group
-o preserve owner
-D preserve device files, preserve special files
-X preserve extended attributes
-A preserve ACLs
-v be verbose
-z use compression
Then there is --delete and --delete-excluded. It means if there is some file on copy, but there is no such file on source, delete file from copy. --delete-excluded means delete all excluded files from copy.

I keep exclusions patterns in separate file. Format is quite simple:
lost+found
*/.Trash/
*/.thumbnails/
cache/
Cache/
.Cache/
.cache/
My share is password protected. Only user franek can access it, and he needs to give his password. If you want to do it by system (e.g. cron), you don't have the possibility to type the password. However, you can put it into file and make file readable only for user (permissions 700). Then you can just point to that file with --password-file option.

Next there is just source and destination. Just like in cp or smb. Source is pretty simple in my example. Destination is a bit more complicated: <user>@<server>::<share-name>

Saturday, August 1, 2009

Setting samba on ubuntu server for sharing files

I am building home server, so now I want to configure it in a way so I could put photos there, and everyone could access them.

I assume samba is already initialized.

Guest access
We want everybody to be able to store files there, and everybody to be able to read them. So let's give guest access to it. But somebody has to be the owner of the files, right? (In terms of Unix file ownership, chown). So we neet to tell who guest user maps to. Lets call our Unix user henry:
sudo adduser henry
Set some password too.

Now, let's tell samba that guest should map to henry. In /etc/samba/smb.conf in [global] section:
guest account = henry
We are ready to create share for everybody now. Again, in /etc/samba/smb.conf:
[for-all]
path = /home/henry
browsable = yes
read only = no
guest ok = yes
create mask = 644
Now we created share called "for-all", it is stored at /home/henry, and everybody can read and write it. Files put to server into for-all share are going to be read-write for owner (henry), and read for everyone. However, it is not so important as everybody can access them like owner through samba.

Users access
We can also make it available only for users. Let's say we want samba user henry:
sudo smbpasswd -a henry
Set password. User created.

Now we need to disable guest access:
guest ok = no
Now we can connect from another machine by smbclient:
smbclient //192.168.1.1/for-all -U henry
Of course put your server's IP instead of 192.168.1.1

Mount as fs for users manually
You can mount samba share to some directory on your client machine. Just like some filesystem. Install smbfs package:
sudo apt-get install smbfs
If you have sudo access, you can mount samba share. First, create directory to mount it:
mkdir smb-share
Now, mount share:
sudo mount -t cifs //192.168.1.1/for-all smb-share -o username=henry,noexec,uid=local_user,gid=local_group
noexec means you'll be not able to run any executable files from that share. uid and gid will render all files in mounted share to belong to user local_user and group local_group on client.

If you want more users to be able to mount the share, you can create group for them:
sudo addgroup samba
Now let's give this group rights to mount remote samba shares. Run:
sudo visudo
And in the group section add following line:
%samba   ALL=(ALL) /bin/mount,/bin/umount,/sbin/mount.cifs,/sbin/umount.cifs
Add user frank to that group:
sudo adduser frank samba
From now on, frank can mount samba shares.

Friday, July 31, 2009

Configure postfix to send emails for root to your account

Goal: make our small ubuntu server forward email which has "to: root" to your private mail.

Install postfix.
sudo apt-get install postfix
Some console app for sending emails can be handy too:
sudo apt-get install mutt
Edit /etc/postfix/main.cf. In mydestination enter host, host.domain, localhost.domain, and also empty domain:
mydestination = serverek.przepompownia.com, localhost.przepompownia.com, , localhost
Restart postfix. I'm not sure if it is really needed, but won't hurt ;)
sudo /etc/init.d/postfix restart
Ok, now edit /etc/aliases. Add something like this:
root: franek
franek: mickey@my.mail.com
Dont forget to run:
sudo newaliases
This way everything sent to root is forwarded to franek, and everything sent to franek is forwarded to mickey@my.mail.com

Now you can try sending some mail to "root". You can use mutt for this.
UPDATE:
Recently my ISP (neostrada, TPSA) blocked outgoing connections to port 25 (standard port for connecting with SMTP servers). What to do to send emails to port 587 is well described here. Author only forgot to add that you also need this:
transport_maps = hash:/etc/postfix/transport
in your main.cf

Tuesday, July 21, 2009

JavaFX - Operations on Strings

Use any quote you like

Ok, so let's start with Strings. You can use both single and double quote to define simple String. Both works:
var a = 'Single';
var b = "Double";
Also you can use another quote in String as part of this String. I.e. if you use single quote to declare String, you can put double quote inside, and if you use double one, you can put single one inside.
var a = 'This is String "with double quote" inside';
var b = "This is String 'with single quote' inside";
Both are valid Strings. However, if you need to use both types in your String, you have to escape it:
var a = 'Here we have "double quotes" and \'single quotes\' in one String';
var b = "And 'here' \"too!\""
Expressions in String

In JavaFX you can also embed expressions in Strings. To do it, put expression in curly brackets:
println("2 + 3 = {2+3}");
This code prints: 2 + 3 = 5 By the way, you can see new println function here. It is in javafx.lang.Builtins, which is included automatically in all JavaFX scripts.

As expression, you can use also variables, function calls, operations on variables (like in example above) etc.

Concatenation

You don't need any operator to concatenate Strings. If you split String over few lines, you don't have to add "+" at the end of each line.
var one = "This" 'is'
"one"
'String';
println(one);
And it outputs: ThisisoneString

Formatting

You can quite easy format Strings in JavaFX. It is based on java.util.Formatter class.

println("{%x 12}");
println("{%c 120}");
var d = Date{};    //Here new java.util.Date is created
println("{%tH d}:{%tM d}:{%tS d}")
And it prints:
c x 23:12:18 First there is 12 in hex, then there is character, which code in Unicode is 120, and then it is Date object, first we get hour from it, then minute, and then second.

Localization

Localization in JFX is realized by properties files. It's name is connected with your script (file with your JFX code) by name convention. If your script is House.fx, then your localization file is House_en.fxproperties and it has to be somewhere in the classpath. fxproperties file looks like this:
"dog"="pies"
"cat"="kot"
And then, to use it in script:
println(##"dog");
println(##[cat]"Cat");
If there is fxproperties found, it is used. If not found, default is used. Default is either properties key (like "dog" in above example) or another word (like "Cat", not "cat" which is only fxproperties key).

Tuesday, July 14, 2009

JavaFX - Defining simple variables.

Ok, so I thought to write JavaFX tutorial. Hope it's going to be useful for somebody. Welcome to part one, about language basics, defining variables and values.

First, you should know what variables/value types are available. There are all the familiar ones (String, Long, Double etc.), but no primitives (long, double etc.). Well, in JavaFX everything is an object. Really. There is also one new type: Duration. It is especially useful in animations, but we'll get to it later.

So there are variables and values. Values are a little like final constants in Java, but only a little. Value of value ( ;) ) can change, but you can't change it explicitly. It can be changed by binding - we'll talk about it in some later part.

So how do you define variables and values? Quite simple:
var a:Float = 5;
Defines variable a of type Float. We can also do something like this:
var a = 5;
Where is variable's type? Well, you don't need to specify it in such case. Type is inferred automatically by JavaFX Script compiler from value assigned to this variable. Isn't it obvious that it is Integer? It could be also Float, yes, and if you want it to be Float, please specify it like in first example.

What about "almost-like-java-constants" values? You define it like that:
def a:Float = 5;
So now there is value defined, and you can't change it. a = 6 will not compile.

Ok, let's look at this new Duration type. Few examples:
var s = 5s;
var m = 2m;
var h = 4h;
s is 5 seconds, m is 2 minutes and h is 4 hours. Quite simple, isn't it? Also arithmetics like adding, multiplying etc works here:
var s = 5s * 4;
var m = 2m + 3m;
var h = (2h + 3m) * 4;
Ok, that's all in this part. In the next one I'll write something about String operations and sequences. Stay tuned!

Monday, July 6, 2009

Review: JavaFX in Action, by Simon Morris

JavaFX in Action JavaFX (JFX) is a new technology. There are not many books about it yet. Then the more happy I am I can read one of them - "JavaFX in Action" by Simon Morris from Manning Publications.

At the beginning of the book there is explanation of what JavaFX platform is, and it's language JavaFX Script. And why it is great at creating GUIs. The next step is not language basics as one could expect, but first small application in JavaFX. You don't fully understand how it works and what all this words, numbers and braces mean, but you can run it and say "WOW!" :) It is there to make an impression, and it serves this purpose well. It's like an appetizer, making you even more hungry for knowledge and more eager to learn this new great language. I like it, because it makes further reading "taste" better. It also shows what is told in first chapter is true - in JavaFX you can create fancy graphical effects easily.

Chapters two and three are about language itself, variables declaration, data types (new one: duration), language structure - all the fun begins. After learning basic stuff about language, we start creating "real" applications. Nice looking, fancy and colorful small applications (JavaFX is for GUI, isn't it?). What I didn't like here is a bit waterfall, not iterative process. All applications are created class by class, and then at the end run. Many times I wanted to see how single component looks like before finishing whole application. I could do it by writing small app by myself, but I'd prefer to see it in book.

The language used in the book is very light, even funny. It is pleasure to read, still everything is explained clearly and understandably. One of difficult topics are transformations. Such constructs are not common and I didn't see them in any other language (at least not done this way). For me it was quite difficult topic, yet everything was well explained. I understood transformations after playing a little with the code. Another thing was new data type "duration" - no problems with understanding here too (but this one was much easier).

I like it when in book you can see effect of running application. So you don't need to code or even copy code from sources attached to the book and run it. In this book there always was output included after source code, or there were pictures if output was not on console. You still can copy code to your favorite IDE and see it running, but you don't have to.

The book I read was based on JFX 1.1, while there is 1.2 available now. However it was MEAP version, and I'm sure final version is going to be based on 1.2 or even newer JFX (depending when it is going to be released). Anyway author has a lot of knowledge and he predicted (or just knew about it) many things that were missing in JFX 1.1 but are available in 1.2.

Appendixes are also great. There is one for people who don't have anything installed yet, just opened the book and want to code. I had everything installed before, but if you don't, don't worry, the book will tell you what to do step by step. I often missed such appendix in other books, especially when I was less experienced developer. There is even appendix for people not familiar with java, so you can see what static typing vs dynamic typing is all about, what are packages etc.

Reading this book was a pleasure. I learned a lot, and by the best and most effective way - by having fun :)

Friday, June 12, 2009

JAVArsowia 2009

Next edition of JAVArsovia conference is getting closer :) Schedule looks amazing! Four tracks, and everything for free! What a pity I (probably) can't go there this year :( I would love to see presentations on testing and TDD (quite many presentations related to testing this year), Apache Wicket, Android, JVM virtualisation...

I know some speakers, not all of them, but the ones I know are great, so I assume the others are the same :) Also I wouldn't miss evening meeting, drinking beer, talking with fellow geeks and meeting new ones.

Well, I won't be there, but YOU still can :) I am pretty sure you won't regret it :)

Tuesday, June 9, 2009

Encoding movies (in ubuntu)

Example command to encode movies in ubuntu.
mencoder input-movie.avi -o output-movie.avi -oac mp3lame -mc 0 -ovc x264 -x264encopts bitrate=45000
You need to have mencoder installed. mp3lame is audio codec, x264 is video codec. To see other possible codecs type
mencoder -ovc help -ova help 
-mc 0 is for not messing with audio synchronization. Without it mencoder tries to synchronize audio with video, and it can break the synchronization. So if in source movie audio was synchronized well include this option. After -x264encopts there are x264 codec options. Other codecs have other options.

Mencoder howto site was helpful while looking for all this information.

Sunday, May 31, 2009

JavaFX is statically typed. Scala is statically typed.

Sometimes people are suprised when they read or hear that Scala and JavaFX are statically typed languages. Probably it is because in this languages you can declare variables without explicitly telling the type, like this:
//It looks exactly the same in JavaFX and Scala
var a = "string";
No type is given, yet compiler knows a is String (at compile time). How does it know? Well, we just assigned value of type String to it, didn't we? When declaring some variable and immediately assigning value to it, you don't have to add type to the declaration.

Saturday, May 23, 2009

Be careful binding to functions in JavaFX

In JavaFX (I'll call it JFX from now) there is possibility to bind variables. You can bind variable to another variable:
var src = 4;
def dst = bind src;
println(dst);
src = 42;
println(dst);
it'll print:
4
42
Maybe you noticed I used var for one variable and def for another. It could be as well var in both cases. Bind makes dst is updated every time it is read. Here we bound variable to another variable, but we can bind it to any expression:
var factor = 3;
var multiplier = 3;
def dst = bind getValue(multiplier);
println(dst);
multiplier = 5;
println(dst);

function getValue(p:Integer) {
 p * factor;
}
What it gives us?
9
15
Still everything is quite clear, isn't it? First value of dsc is 3*3, which is 9, than multiplier is changed and we get 5 * 3, which is 15. Let's now change factor, not multiplier:
var factor = 3;
var multiplier = 3;
def dst = bind getValue(multiplier);
println(dst);
factor = 5;
println(dst);

function getValue(p:Integer) {
 p * factor;
}
And we get:
9
9
Now this is wrong! First we want 3*3 which is 9, so it is ok, but then we change factor and expect 3*5, which is 15, but we still get 9. What's up? Well, dsc is bound to function. JFX remembers our function was called last time with parameter 3, and returned 9. Second time (second read of dst) it is also called with parameter 3, so JFX doesn't call it again, but just gives us cached value. But there is something we can do about it, and it is the bound keyword:
var factor = 3;
var multiplier = 3;
def dst = bind getValue(multiplier);
println(dst);
factor = 5;
println(dst);

bound function getValue(p:Integer) {
 p * factor;
}
And now it prints:
9
15
Just as expected. bound keyword makes JFX analyse the function and checks which variables can affect return value. In this case it can recoginze return value is dependent not only on input parameter, but also on factor variable, so when variable changes, JFX calls the function again even if the parameter doesn't change. Now consider a little different code:
var factor = 3;
var multiplier = 3;
def dst = bind getValue(multiplier);
println(dst);
Thread.currentThread().sleep(5);
multiplier = 5;
println(dst);
Thread.currentThread().sleep(5);
println(dst);

function getValue(p:Integer) {
 System.currentTimeMillis();
}
Note that function is not bound again. sleep(5) is there to make sure two calls won't happen in the same millisecond. So it can give us:
1243112189488
1243112189496
1243112189496
(of course you'll get different values if running it at different time) First is number of milliseconds, second is again proper number of milliseconds, because function parameter value has changed and JFX called function again, and then second value is repeated, because parameter value didn't change and function return value is taken from cache. But what happens when we'll use bound? Let's see:
var factor = 3;
var multiplier = 3;
def dst = bind getValue(multiplier);
println(dst);
Thread.currentThread().sleep(5);
multiplier = 5;
println(dst);
Thread.currentThread().sleep(5);
println(dst);

bound function getValue(p:Integer) {
 System.currentTimeMillis();
}
And we get:
1243112415228
1243112415228
1243112415228
What? All three values are the same? So adding bound even made things worse! How is it possible? Well, bound makes JFX not only can recognize which variables affect return values, but also which function parameters doesn't affect it. So now JFX is aware that p doesn't affect return value of the function and it calls the function only on the first time. Then it takes value from cache, regardless parameter has changed or not. Conclusion: Be careful when using functions for binding variables. Be extremely careful when using functions dealing with current time (or better just don't do it ;)).

Friday, May 22, 2009

JavaFX for linux

There is no official release of JavaFX for linux. Yet you can use it thanks to Silveira Neto. Here is his blog entry with plugins for Netbeans.

All you need to do is download the plugins, extract and install in Netbeans 6.5.x (doesn't work on 6.7 beta). You also need java 1.6 update 13.

Sunday, May 17, 2009

Key promoter for Eclipse

Did you ever miss key promoter in Eclipse? I did. Fortunately I found one: Mousefeed

Whenever you do some action with your mouse, and there is keyboard shortcut for this action, the shortcut is displayed:

English from now on

Z tych samych przyczyn co Paweł Szulc, przechodzę na angielski. Mam nadzieję, że nie ubędzie mi przez to czytelników.

Monday, May 11, 2009

GeeCON - wrażenia (jak najbardziej pozytywne)

Ostatnio (7-8 maja) byłem na konferencji GeeCON w Krakowie. Rewelacja! Prawdę mówiąc, nigdy nie byłem na tak dużej i tak dobrej konferencji. Poziom prelegentów naprawdę wysoki, organizacyjnie także wszystko super.

Osobiście najbardziej podobała mi się prezentacja Bruno Bossoli "SOLID design principles". Temat bardzo ważny, widać że ludziom brakuje takiej wiedzy, a jednak niewiele można o tym znaleźć. Może dlatego, że nie tak łatwo o tym napisać, nie jest to taka konkretna wiedza jak "jak zrobić X w technologii Y". Bruno wyłożył ją ze swobodą i humorem. Kilka razy sala wybuchała śmiechem, jak na dobrej komedii :)

Wrażenie zrobiła na mnie także Java FX pokazana przez Adama Biena. Muszę się bliżej zainteresować tym językiem.

Prezentacja o Scali była chyba przewidziana dla trochę innego audytorium. Odniosłem wrażenie, że Luc Duponcheel to naukowiec, zajmujący się problematyką języków programowania na codzień i znający je od podszewki, przez co wszystko wydaje mu się banalnie proste. Dla słuchaczy jednak takie nie było. Mimo wszystko utwierdzam się w przekonaniu, że trzeba się tym językiem zainteresować bliżej.

Miško Hevery przedstawił kilka ciekawych problemów dotyczących testowania. Dowiedziałem się m.in., że TDD jest jak seks - jeśli nie sprawia Ci przyjemności, znaczy że źle to robisz ;) Poznałem też ciekawe narzędzie, którego chciałbym zacząć używać w firmie w której pracuję. Mianowicie testability-explorer - narzędzie pokazujące na ile kod jest "testowalny". Tak się składa, że testowalność kodu przekłada się na jego dobry design, więc jest to istotna metryka.

O Groovym co nieco już wiedziałem. Właściwie to uczyłem się Ruby'ego, ale okazało się, że Groovy jest jego kalką :) Nie wiedziałem natomiast, że kompilator Groovy'ego akceptuje składnię Javy. Oznacza to, że możemy klasę w Javie zamienić na klasę w Groovym (przez zmianę rozszerzenia pliku lub skopiowanie jego zawartości) i stosować składnię Groovy'ego tylko tam gdzie chcemy, stopniowo. Widziałem też, że ludzie, którzy wcześniej nie widzieli Groovy'ego/Ruby'ego, byli zachwyceni :) Fakt, skrócenie 6 linii kodu do jednej robi wrażenie :)

Kolejne narzędzie, które chętnie wypróbowałbym w firmie to Gradle. Z tym jednak nie będzie już tak łatwo, bo nie da się tego "dołożyć" do istniejących struktur. Jeśli budujemy projekt mavenem, to zastosowanie Gradle'a wiązałoby się z całkowitą rezygnacją z mavena, a to nie będzie proste. Tym niemniej narzędzie jest warte zainteresowania. Może da się je wykorzystać przy jakimś nowym projekcie jak się pojawi.

Nie wspomniałem jeszcze o szkoleniu. W ramach konferencji można było po promocyjnej cenie (naprawdę niskiej - 100zł) wziąć udział w szkoleniu. Ja wybrałem szkolenie z Web Services, choć teraz trochę żałuję że nie z Java FX. Cóż, pozostają książki i internet.

Nie mogę także nie pochwalić się pierwszym certyfikatem z Javy - BE-004. Jest to certyfikat potwierdzający udział w "Java Beer Advanced Training" :)

Pozostaje mi podziękować jeszcze raz organizatorom za świetną konferencję. Było naprawdę super, kto nie był ma czego żałować.

Monday, April 6, 2009

Konferencja java4people 2009 - zakończenie

Zakończyła się druga edycja konferencji java4people. Teraz organizatorzy mogą odetchnąć, choć nie do końca, bo jeszcze trzeba wrzucić na stronę materiały, zdjęcia, a za jakiś czas filmy. Na filmy trzeba będzie trochę poczekać, niestety montaż musi potrwać. Dobrą wiadomością natomiast jest to, że będą udostępnione na parleys.com!

Z ciekawych wiadomości dodam jeszcze, że krótka relacja z konferencji pojawiła się w Radiu Szczecin.

Dziękujemy za przybycie prelegentom. Wszyscy spisali się na medal, nie byliśmy w stanie śledzić wszystkich prezentacji, ale wiem że były na wysokim poziomie.

Osobiście bardzo podobała mi się prezentacja Pawła Szulca o testowaniu ogólnie, i o testowaniu EJB 3.0 szczególnie. Paweł, oprócz niezbędnej wiedzy, ma też talent do opowiadania z humorem, luzem, tak że nawet ktoś kto nie orientuje się w Javie nie nudzi się na jego wystąpieniach.

Jako drugi prelegent wystąpił Waldemar Kot. Dobrze, że prezentację na temat Comet&Bayux już widziałem, bo tym razem nie mogłem w niej uczestniczyć. Rozmawialiśmy przez ten czas z redaktorem Jarkiem Daleckim i wnosiliśmy pizzę. Mam nadzieję, że smakowała i że nikt nie pozostał głodny.

Na prezentację o systemie kontroli wersji GIT szczególnie czekałem. Od jakiegoś czasu interesował mnie ten system i cieszę się że wreszcie mogłem się czegoś więcej o nim dowiedzieć. Ożywiona dyskusja w czasie wystąpienia Andrzeja Śliwy pozwoliła na spojrzenie z różnych punktów widzenia. To właśnie jest najlepsze na konferencjach.

Jacek Laskowski jak zwykle "dał czadu" i "zrobił show". Trzeba mieć sporo odwagi żeby zrobić prezentację opartą tak mocno na "żywym kodzie". Wiadomo, że zawsze coś może nie zadziałać. Tak też stało się i tym razem. Trzeba też mieć dużą wiedzę żeby z takich problemów wybrnąć, i świetny kontakt z publicznością, żeby pozostawić dobre wrażenie nawet jak wybrnąć się nie uda.

Jako ostatni (last but not least) wystąpił Maciek Majewski przedstawiając Spring Webflow w przykładach. Tej prezentacji również nie mogłem śledzić, a szkoda, bo temat dla mnie interesujący. Dobrze że będą filmy.

Zawiodła niestety klimatyzacja, co dało się odczuć szczególnie pod koniec. Mimo wszystko chyba wszyscy uczestnicy zostali do końca, dzięki czemu mogli wziąć udział w losowaniu nagród w postaci książek, licencji na programy i wejściówki na konferencję GeeCON. Żeby jeszcze bardziej "zareklamować" konferencję dodam, że każdy uczestnik dostał pakiet "Nootebook security" od firmy G DATA, sponsora java4people. Nie wspominając o koszulce.

Zapraszamy za rok!

Friday, March 13, 2009

Mój artykuł w JavaEXPRESS

Napisałem ostatnio artykuł o GWT dla JAVA exPress, a Grzegorz Duda zdecydował się nawet go zamieścić :) Zatem zapraszam do lektury, bynajmniej nie tylko mojego artykułu, bo JAVA exPress to świetna gazeta o Javie, w dodatku za darmo.

Thursday, February 26, 2009

Java4people zbliża się

Zbliża się druga edycja organizowanej przez Szczecin JUG konferencji java4people. Jest już uruchomiona strona http://www.java4people.com, na której można się zarejestrować, zatem zapraszamy :)

Będzie o EJB3, Comet & Bayeux, Grails, Spring Webflow i GIT. Same ciekawe prezentacje, a i prelegenci zacni. Waldemar Kot, Jacek Laskowski, to ludzie bez których polska społeczność skupiona wokół Javy byłaby znacznie uboższa.

Ja osobiście niecierpliwie czekam na prezentację o Grails, języki dynamiczne mnie ostatnio ciekawią.

Do zobaczenia na konferencji!