luni, 24 august 2009

Richfaces and JQuery

Richfaces este un framework bazat pe JSF care ofera o gama larga de componente "ajax-enabled". Componentele din acest framework utilizeaza libraria javascript prototype. Din acest motiv trebuie sa aveti grija in momentul in care doriti sa folositi JQuery. In acest weekend, am avut nevoie sa folosesc componenta dataScroller din richfaces precum si galeria foto lightbox(plugin pentru jquery). Nu mica mi-a fost mirarea in momentul in care componenta dataScroller nu mergea asa cum era de asteptat(linkurile paginilor nu mergeau si apareau erori javascript). Dupa ce am cautat pe internet si am citit si in referinta oficiala am aflat ca trebuie sa importam jquery intr-un mod specific richfaces:

<a4j:loadScript src="resource://jquery.js" >

In functiile javascript, daca aveti nevoie de functionalitati JQuery, folositi functia jQuery(.....) in loc de $(...). In aceasta maniera orice conflict dintre jQuery si prototype este rezolvat.

miercuri, 19 august 2009

Python SQLAlchemy ORM

Zilele trecute a trebuit sa implementez niste entitati care sa mapeze tabele dintr-o baza de date la o logica obiectuala. In Java, acest lucru il fac utilizand Hibernate. In Python am ales sa folosesc SQLAlchemy. La inceput sintaxa a fost un pic derutanta dar dupa ce m-am obisnuit cu ea a fost extrem de usor sa implementez clasele de care aveam nevoie. Ca backend am folosit o baza de date Oracle XE. In continuare voi arata cum se poate implementa o relatie one-to-many si cum se pot implementa query-uri utilizand SQLAlchemy. Pentru a face lucrurile un pic mai interesante voi utiliza o cheie primara compozita. Voi presupune ca implementam entitatile in pachetul da.

1. In fisierul __init__.py am ales sa instantiez dependentele sqlalchemy ce vor fi folosite in fiecare entitate.

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

BaseEntity = declarative_base()
strDbURL = "oracle://db_tes:xxx@xe"
objDbEngine = create_engine(strDbURL, echo=False)

Session = sessionmaker(bind=objDbEngine)
Session.configure(bind=objDbEngine)

def getConnection():
return Session()

In acest moment putem incepe sa implementam entitatile. Fiecare entitate va extinde BaseEntity. De fiecare data cand vrem sa obtinem o conexiune la baza de date utilizam metoda getConnection(). O sessiune SQLAlchemy este asemanatoare cu o sesiune Hibernate.

2. Definim o clasa utilizator care are ca si cheie primara(username si parola --- nu faceti asa in practica: puteti alege cnp-ul ca metoda de identificare). Aici vreau doar sa demonstrez utilizarea cheilor compozite.

from da import BaseEntity
from sqlalchemy import Column,Integer,String,Numeric,DateTime,ForeignKey,Sequence
from sqlalchemy.orm import relation, backref

class User(BaseEntity):
username = Column("username", String, primary_key=True)
password = Column("password", String, primary_key=True)
descriere = Column("descriere", String)

def __init__(self, strUsername, strPassword, strDesc):
self.username = strUsername
self.password = strPassword
self.descriere = strDesc

3. In continuare implementam clasa adresa.

from da import BaseEntity
from sqlalchemy import Column,Integer,String,Numeric,DateTime,ForeignKey,Sequence
from sqlalchemy.orm import relation, backref

class Adress(BaseEntity):
id = Column("id", Integer, Sequence("seq_xxx_id"), primary_key=True)
fk_username = Column("fk_username", String, ForeignKey("utilizatori.username"))
fk_password = Column("fk_password", String, ForeignKey("utilizatori.password"))
street = Column("street", String)
number = Column("number", String)

user = relation("User",
foreign_keys=[fk_username, fk_password],
primaryjoin="User.username == Address.fk_username and "
"User.password == Address.fk_password",
backref="adresses")

def __init__(self, strUser, strPasswd, strStreet, strNumber):
self.fk_username = strUser
self.fk_password = strPassword
self.street = strStreet
self.number = strNumber

Observatii: in acest exemplu incerc sa demonstrez puterea si flexibilitatea pe care o ofera SQLAlchemy. In primul rand, in orice entitate SQLAlchemy vom defini structura tabelei mapata la atribute ale entitatii. Utilizarea functiei relation permite implementarea legaturilor de tip one-to-one, one-to-many si many-to-many. De asemenea, utilizarea argumentului keyword backref indica frameworkului sa adauge automat un atribut la capatul celalalt al relatiei.

4. Dupa ce am implementat toate entitatile trebuie sa le si folosesc. In exemplul de mai jos arata o succesiune de linii de cod care demonstreaza functionalitatea entitatilor.

import da
from da import User, Address

# query pentru a selecta toti utilizatorii din bd
objSes = da.getConnection()
for objUsr, in objSes.query(User).all():
print(objUsr.addresses)

# query pentru a conditiona returnarea unui utilizator care are o anumita adresa
for objUsr in objSes.query(User, Address).filter(User.username == Address.fk_username and User.password == Address.fk_password).filter(Address.id == 1).all():
print(objUsr.username)

In concluzie, SQLAlchemy faciliteaza maparea tabelelor in logica obiect(la fel ca orice ORM) dar nu necesita un fisier de configurare separat sau anotari suplimentare(precum Hibernate). De asemenea, scrierea de query-uri este extrem de usoara. Ceea ce nu s-a aratat dar este intuitiv este adaugare de noi entitati in bd. Pentru aceasta folositi objSes.add(objInstance). Folositi add chiar daca vreti sa faceti update(SQLAlchemy va sti ce doriti sa faceti in functie de atributele setate in instanta).

vineri, 7 august 2009

Java si mocking - PowerMock

In unele posturi precedente am vorbit despre cum puteti testa cod python prin eliminarea dependentelor. Acelasi lucru il puteti face si in java desi este un pic mai complicat. Dupa ce am studiat mai multe librarii pentru mock am ajuns la concluzia ca PowerMock se apropie cel mai mult de libraria mocker pentru python. Aceasta librarie aduce imbunatatiri pentru EasyMock iar in ultimele versiuni vine cu suport si pentru Mockito. Printre principalele functionalitati ale PowerMock mentionez:
  • mock pentru functii statice
  • mock pentru functii private
Aceste doua elemente sunt extrem de importante si greu de realizat in alte framework-uri. Pentru a intelege mai bine cum se utilizeaza PowerMock prezint urmatorul exemplu:

class Calculator {
public static int add(int a1, int a2) {
return a1 + a2;
}
}

class Operatii {
public int operatieComplexa(int a1, a2) {
int a = Calculator.add(a1, a2);
return ++a;
}
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({Calculator.class})
class TestOperatii {
@Test
public void testOperatieComplexa() {
PowerMock.mockStatic(Calculator.class);
EasyMock.expect(Calculator.add(1, 2).andReturn(3);

PowerMock.replayAll();

Operatii obj = new Operatii();
int ret = obj.operatieComplexa(1, 2);

PowerMock.verifyAll();

Assert.assertEquals(4, ret);
}
}

Asta e tot. In momentul in care se executa testul in loc sa se foloseasca metoda statica add din clasa Calculator se foloseste o metoda injectata. Cateva elemente interesante sunt enumerate mai jos:
  • @RunWith(PowerMockRunner.class). Indica JUnit sa foloseasca clasa PowerMockRunner pentru rularea testelor(nu merge fara asta datorita faptului ca PowerMock implementeaza un class loader custom).
  • @PrepareForTest({Calculator.class}). In aceasta anotare se enumera clasele pentru care se va face mockStatic.
In concluzie, PowerMock este un framework puternic de testare care implementeaza fazele record/replay/verify asa cum face si mocker pentru python. Pentru mai multe detalli vizitati: http://code.google.com/p/powermock/w/list