pondělí, dubna 14, 2008

Grails a Service Layer

Jedním z pilířů frameworku Grails je SpringFramework. Jeho možnosti jsou integrovány na různých místech Grails frameworku. Dneska se podíváme na tzv. “Service Layer”. Kdo Spring Framework někdy použil, tak s velkou určitostí využil jeho možnost tvorby instancí objektů. Tato vlastnost je označována zkratkou IOC(inversion of control). Jednoduše řečeno, Spring vám vytvoří a udržuje objekty s různou “životností” jako je singleton, request, session atp.
Při použití v Javě většinou musíme vytvořit samotnou třídu a její XML deklaraci pro Spring.

V Grailsech je tato Spring infrastruktura dostupná a Groovy je použit jako DSL. Použití je jednoduché. V adresáři projektu Grails vytvoříme Service objekt, který v sobě ponese jak kód samotný, tak i konfiguraci.

Prázdný soubor pro nově definvanou službu vytvoříme takto:

grails create-service FileStorage

Samotná služba může vypadat například takto:(komentáře jsou vloženy do kódu)

// jelikož si Grails s JAVOU velmi dobře rozumí, můžeme přímo importovat JAVA knihovny
import org.springframework.web.multipart.MultipartFile
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.codehaus.groovy.grails.commons.ConfigurationHolder

class FileStorageService {
// služba může být transakčně oddělena od zbytku kódum nyní to ale nevyužijeme
boolean transactional = false
// Grails nám danou službu mohou vytvořet s různou životností: session, prototype, flash, singleton ...
static scope = 'singleton'

// A zde už máme samotné metody služby
// store file into directory
def add_to_store(MultipartFile file, String file_path, String file_name) {
def full_path=ConfigurationHolder.config.fileStorage.uploadDir+”\\”+file_path
def d2= new File(full_path)
d2.mkdirs()
file.transferTo(new File(full_path+”\\”+file_name))
}

// remove file from storage
def remove_from_store(String file_path){
def f=new File(ConfigurationHolder.config.fileStorage.uploadDir+”\\”+file_path)
if (f.exists()){
f.delete()
}
}

// download file
def downloadFile(String file_name, String file_path, response){
response.setContentType(”application/x-download”);
response.setHeader(”Content-disposition”, “attachment; filename=” +file_name);
def f=new File(ConfigurationHolder.config.fileStorage.uploadDir+”\\”+file_path)
f.withInputStream{response.outputStream << it}
}
}

sobota, listopadu 17, 2007

Znáte GRAILS?

GRAILs je webovým frameworkem založeným na jazyce Groovy. O Groovy se psalo na root.cz například zde. Myslím že Groovy se může stát populárním podobně jako Ruby právě díky webovému frameworku. Zajímaví je ovšem samotný framework GRAILS. V současnosti se blíží k verzi 1.0 a jedná se už o poměrně stabilní prostředí. GRAILS jsou založeny na JAVA technologiích jako jsou Spring Framework a Hibernate a v podstatě pomocí jazyka Groovy tvoří přívětivý uživatelský aparát pro práci s nimi. Přívětivý do té míry, že se v mnoha věcech 'podobá' Ruby on Rails, který tvoří v současnosti určitou laťku pro rychlý webový vývoj. Podobnost je spíše filozofická než technická. Současní vývojáři si mohou vzít mnoho příkladů z uspěšných nástrojů frameworků jako jsou Ruby On Rails, Django atp. A GRAILS je to vidět.

Na Grails se mi líbí několik vlastností:
  • GORM = ORM založený na Hibernate pro práci s databází. Zvláště se mi libí možnost automatické aktualizace schématu databáze podle definice objektu v Grails. Způsob práce vychází z filozofie ActiveRecord
  • integrovaný scheduler - opět jako i jiné komponenty Grails je založen na existujícím projektu Quartz. Jednoduše si nadefinujete periodicitu spouštění a spouštěný kód má přistup k celému prostředí Grails.
  • systém pluginů - už nyní najdete pluginy pro autentizaci, práci s obrázky atp. Zde je prostor pro celou komunitu rozšířovat celý systém. Pro Ruby On Rails dneska existují stovky pluginů.
  • systém development, test a production prostředí, pro které si mohu nadefinovat připojení na jiné databáze. Mohu tam velmi lehce provozovat a přepínat mezi vývojovou verzí databáze z testovacími daty a produkční databází.
  • dokumentace - ta je psána průběžně již od počátku projektu. K sehnání je již i kniha 'The Definite Guide to GRAILS' a pro Groovy jako takové k dispozici s nakladelství Manning 'Groovy in Action'. Pěkný je i reference guide.
Z podstaty jazyka Groovy vychází možnost používat existující JAVA knihovny a implementovat je do vaší GRAILS aplikace. Pokud tak třeba chcete používate JFreeChart, není to problém. To co je však vynikající je možnost celou aplikaci jednoduchým příkazem zabalit do WAR souboru( 'grails war') a nechat pak běžet na některém z celé řady JAVA serverů(Apache Tomcat, Jboos, Resin, WebSphere atp.) . Aplikaci v Grails je tak možno lehce integrovat do existujícího firemního JAVA prostředí. (pokud nějaké existuje).

Zde jsem zmínil opravdu jen minimum z toho, co Grails nabízí. Zájemci mohou navštívit přímo stránky projektu na adrese www.grails.org a projít si další detaily.

Pro fajnšmekry uvádím i trochu kódu. Ten ukazuje jak definovat databázové objekty a jejich jednoduché vazby mezi sebou. Taktéž si zde v můžete nadefinovat různá omezení a podmínky pro jednotlivé položky modelu. Z vaší definice v Grails is systém vytvoří předpis pro Hibernate a provede aktualizaci databáze.


// objekt dokumentu
class Document {

static hasMany = [ attachments : Attachment]
String title
String description
String category
Integer att_count
String category1

static constraints = {
title(unique:true, blank:false)
category(blank:true)
category1(blank:true, nullable:true)
att_count(blank:true, nullable:true)
}
}


// příloha, která patří k dokumentu
class Attachment {
String title
String description
Document document

static constraints = {
title(blank:false)
}
}

pátek, září 21, 2007

Apache Cayenne - easier user API

I really like ActiveRecord and I'm also watching the ActiveObjects ORM(JAVA). This project is very nice but still not mature enough for the real life project. But being inspired from the ActiveObjects I created a wrapper for Apache Cayenne that uses EntityManager approach. Instead a common DAO like scenario of using services for each model, I can now use one EntityManager that serves for all models.

The solution requires Java 5 as generics and some other features are being used.
Here are just a few code snippets of how it can be used.


Various syntax examples:

EntityManager em;
// create and save object
Contact contact=em.create(Contact.class);
em.saveChanges();

// find object by id
Contact contact=em.findById(Contact.class, id);

// find object by property
Contact contact=em.findFirstByProperty (Contact.class, "username", form.getFieldValue("username"));

// find many objects by property
List contacts=em.findAllByProperty(Contact.class, "subdomain.name", form.getFieldValue("subdomain"));

// find objects based on user defined query
List contacts=em.findAllByQuery(
Contact.class,
Query.where("subdomain = $subdomain and age > $age")
.param("subdomain", current_user.getSubdomain())
.param("age",18)
.order("lastname",true)
.offset(200)
.limit(10)
.include(Contact.ROLE_ARRAY_PROPERTY)
);
Its just a special API interface that let you work with Apache Cayenne in very easy way.
I can share the code if someone find it usefull.