iPhone: NavigationController e Session Manager

iphone-guitarBentornati su devme! In questo articolo volevo parlare di una strategia che ho impiegato nel progetto di lavoro di cui mi sto occupando, che tratta dello sviluppo di un’applicazione per iPhone (e altre piattaforme), e del quale spero se ne sentirà parlare. Non presenterò una discussione sul funzionamento dell’applicazione, ma di un aspetto particolare che ho utilizzato per risolvere un problema. Volevo proporre la mia soluzione (sicuramente ne esisteranno delle altre più ottimizzate) e discuterne con chi ne fosse interessato.
L’analogia che si può riscontrare è quella web. Si pensi ad esempio alla navigazione tra pagine web, ciascuna delle quali visualizza il suo contenuto sulla base delle scelte effettuate nelle pagine precedenti. Nel contesto di un’applicazione molto semplice si potrebbe far uso delle Sessioni messe a disposizione dal linguaggio utilizzato per lo sviluppo (es. php). Il valore selezionato nella prima pagina viene memorizzato in Sessione e recuperato nella pagina finale per l’estrazione dei dati di dettaglio, di un’ipotetica scheda prodotto. Nella mia applicazione ho utilizzato la stessa tecnica, in questo contesto mi è sembrata la più semplice…ovviamente ditemi se esiste di meglio :)
L’applicazione è molto varia, utilizza molti componenti messi a disposizione dall’ SDK iOS, e cioè TabbedBar, NavigationController, gestione degli eventi, TableViewController, ricerche su tabelle e altro. Nello specifico, tratteremo della navigazione attraverso delle view utilizzando il NavigationController.
Ma passiamo al codice: 

@@ SessionManager.h @@
 
#import <Foundation/Foundation.h>
#import "SessionObject.h"
 
@interface SessionManager : NSObject {
 
	NSMutableDictionary *session;
}
 
@property (nonatomic, retain) NSMutableDictionary *session;
 
/** 
 * Get singleton instance of Session Manager.
 */
+(SessionManager*) getInstance;
 
/**
 * Init session object.
 */
-(void) initSession;
 
/**
 * Put object into session.
 */
-(void) put: (NSString*)key object:(NSObject*)object;
 
/**
 * Retrieve object from session if exists.
 */
-(NSObject*) get: (NSString*)key;
@end
 
#import "SessionManager.h"
 
@@ SessionObject.m @@
 
@implementation SessionManager
 
@synthesize session;
 
static SessionManager *instance = nil;
 
+(SessionManager*) getInstance {
    @synchronized([SessionManager class]) {
        if (!instance)
            [[self alloc] init];
	return instance;
    }
    return nil;
}
 
+(id) alloc {
    @synchronized([SessionManager class]) {
        NSAssert(instance==nil, @"Attempted to allocate a second instance of SessionManager singleton");
	instance = [super alloc];
	return instance;
    }
    return nil;
}
 
-(id) init {
    self = [super init];
    if (self != nil) {
	[self initSession];
    }
    return self;
}
 
-(id) retain {
    return self;
}
 
-(void) initSession {
    session = [[NSMutableDictionary alloc] init];
}
 
-(NSObject*) get:(NSString *)key {
    NSObject *obj = [session objectForKey:key];
    return obj;
}
 
-(void) put:(NSString *)key object:(NSObject *)object {
    [session setObject:object forKey:key];
}
 
@end

La prima parte del codice fa riferimento alla definizione del file header per la classe SessionManager, ovvero la classe che memorizzerà le informazioni in sessione. La classe è un singleton, esattamente indentica a quella vista in questo articolo. Possiede un’unica variabile membro, un array associativo NSMutableDIctionary che consente la memorizzazione di oggetti in sessione, allo stesso modo in cui avviene ad esempio in php ($_SESSION["key"] = $value). Nel nostro caso il valore in sessione viene memorizzato attraverso l’invocazione del metodo put, il quale prende in input 2 parametri, la chiave e il valore e lo memorizza in Sessione. Il metodo simmetrico, consente di estrarre il valore dalla sessione attraverso la specifica della chiave. Possiede i metodi di inizializzazione che consentono di allocare e inizializzare l’array associativo.

Consideriamo ora di aver creato una classe NavigationController per permettere la navigazione tra le diverse view, e che la prima delle nostre view sia di tipo UITableViewController. Senza scendere nei particolari vediamo solo i metodi più signitficativi della nostra classe:

#import "DevmeTableViewController1.h"
 
@implementation DevmeTableViewController1
 
@synthesize devmeTableViewController2;
 
- (void)viewDidLoad {
    [super viewDidLoad];
    //&nbsp;Populate datasource table with Car object
    [self loadTableContent];
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Tabella1" style:UIBarButtonItemStylePlain target:nil action:nil];
    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];
    self.navigationItem.title = @"Dati tabella 1";	
}
 
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
    // Configure the cell...
    Car *car = [datasource objectAtIndex:indexPath.row];
    // Display cars brand
    cell.textLabel.text = car.brand;
    return cell;
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    Car *car = [datasource objectAtIndex:indexPath.row];
    session = [SessionManager getInstance];
    [session put:@"BRAND" object:car.brand];
 
    DevmeTableViewController2 *tvController = [DevmeTableViewController2 alloc];
    self.devmeTableViewController2 = tvController;
    [tvController release];	
    [self.navigationController pushViewController:self.devmeTableViewController2 animated:YES];
}
 
..... other methods defined here.....
.....
.....
@end

La classe DevmeTableViewController1 visualizza un elenco di marche automobilistiche. La tabella viene popolata dal metodo loadTableContent omesso per semplicità, ma molto semplice da comprendere. Il metodo restituisce l’elenco delle marche automobilistiche estratte da un database popolando l’array datasource. Il metodo interessante per i nostri scopi è didSelectRowAtIndexPath il quale si occupa della navigazione per così dire, da una view ad un’altra. In particolare osserviamo all’interno del metodo che viene selezionato il valore associato alla cella della tabella che è stata selezionata (tapped), estraendolo dal datasource. Lo stesso valore viene salvato in sessione attraverso l’invocazione del metodo put sull’oggetto singleton SessionManager con chiave BRAND.
La view di arrivo è anch’essa una UITableViewController, la quale estrae il valore dalla sessione e popola opportunamente la tabella:

#import "DevmeTableViewController2.h"
 
@implementation DevmeTableViewController2
 
@synthesize devmeTableViewController3;
 
.... other methods here
 
- (void)viewDidLoad {
    [super viewDidLoad];
    session = [SessionManager getInstance];
    NSString *brand = (NSString*) [session get:@"BRAND"];
    self.navigationItem.title = brand ;
    [self loadTableContent:brand];	
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   session = [SessionManager getInstance];
   [session put:@"MODEL" object:[datasource objectAtIndex:indexPath.row]];
 
   DevmeTableViewController3 *vdController = [DevmeTableViewController3 alloc];
   self.devmeTableViewController3 = vdController;
   [vdController release];
   [self.navigationController pushViewController:self.devmeTableViewController3 animated:YES];	
}
 
.... other methods here
@end

Anche in questo caso abbiamo solo i metodi più significativi, viewDidLoad il quale estrae il valore dalla sessione e popola la tabella invocando loadTableContent passando come parametro il valore selezionato in precedenza. Mentre il metodo didSelectRowAtIndexPath preleva il valore selezionato e lo inserisce in Sessione, rendendolo disponibile così alla view successive, infine sposta la navigazione verso l’ultima delle View. Per semplicità non vedremo il codice dell’ultima view, il quale è una ripetizione di quanto già visto. Possiamo considerare l’ultima view una semplice UIViewController, la quale preleva i valori dalla Sessione e invoca un metodo di estrazione dei dati dal database fornendo in input i 2 valori.
E’ tutto. Come vedete delle semplici analogie web possono essere utilizzate nel contesto di un’applicazione per iPhone, rendendo a mio avviso, facile la gestione. Questa applicazione verrà portata anche su dispositivi mobili che montano Android, nei prossimi articoli vedremo qualche esempio di quell’applicazione.
Alla prossima. Stay tuned !

 

Linux command cheat sheet

penguinBuon 2011 a tutti !!
Navigando per la rete ho trovato un interessante insieme di siti i quali elencavano alcune liste dei più diffusi comandi di linux. Ho pensato di raccoglierli e di creare il mio primo cheat sheet, in formato HTML, da pubblicare come articolo sulle pagine del mio blog…sai mai che possa interessare a qualcuno. Ci sono alcuni comandi di uso comune molto chiari, altri molto interessanti da usare solo se la tastiera è la naturale continuazione della proprio mani!

 

Commando Descrizione
apropos whereis Visualizza una descrizione sul comando indicato
man -t man | ps2pdf – > devme_man.pdf Crea un pdf dalla pagina del manuale richiesta
which ls Visualizza il percorso completo del comando
time make Calcola e visualizza il tempo impiego dall’esecuzione del comando
time cat Misura il tempo impiegato per la digitazione (es. scrittura di un testo)
Navigazione delle directory
cd - Vai alla directory precedente
cd Vai alla $HOME directory
(cd dir && command) Vai alla directory indicata, esegui il comando e ritorna alla directory corrente
pushd . Aggiungi allo stack la directory corrent.
pop Estrae dallo stack il percorso dell’ultima directory inserita e ci si sposta
Ricerca dei file
alias l=’ls -al –color=auto’ Elenca le directory facendo l’highlithing degli elementi
ls -lrt Elenca i file per data
find -name ‘*.[ch]‘ | xargs grep -E ‘devme’ Ricerca ‘devme’ a partire dalla directory corrente
find -type f -print0 | xargs -r0 grep -F ‘devme’ Ricerca i soli file che hanno al loro interno la stringa ‘devme’ a partire dalla directory corrente
find -maxdepth 1 -type f | xargs grep -F ‘devme’ Ricerca i soli file che hanno al loro interno la stringa ‘devme’ solo nella directory corrente
find -maxdepth 1 -type d | while read dir; do echo $dir; echo cmd2; done Elabora ciascuna directory trovata a partire dalla directory corrente, ed esegui i comandi contenuti all’interno del ciclo per ciascun elemento
find -type f ! -perm -444 Cerca i file non leggibili da tutti
find -type d ! -perm -111 Cerca i file non accessibili da tutti
locate -r ‘file[^/]*\.txt’ Cerca all’interno della cache tutti i file il cui nome fa match con: *file*.txt
Archiviazione e compressione
gpg -c file Critta il file di input
gpg file.gpg Decritta il file
tar -c dir/ | bzip2 > dir.tar.bz2 Crea un archivio compresso della directory dir/
bzip2 -dc dir.tar.bz2 | tar -x Estrae l’archivio usando gzip al posto di bzip2
tar -c dir/ | gzip | gpg -c | ssh user@remote ‘dd of=dir.tar.gz.gpg’ Crea un archivio compresso crittato della directory dir/ e lo invia sulla macchina remota
find dir/ -name ‘*.txt’ | tar -c –files-from=- | bzip2 > dir_txt.tar.bz2 Crea un archivio del contenuto di dir/
find dir/ -name ‘*.txt’ | xargs cp -a –target-directory=dir_txt/ –parents Crea una copia del contenuto della directory dir/
( tar -c /dir/to/copy ) | ( cd /target/ && tar -x -p ) Copia (preservando i permessi) la directory sorgente nella directory target
( tar -c /dir/to/copy ) | ssh -C user@remote ‘cd /target/ && tar -x -p’ Copia preservando i permessi copy/ dir to remote:/target/ dir
dd bs=1M if=/dev/sda | gzip | ssh user@remote ‘dd of=sda.gz’ Effettua il backup dell’hardisk sulla macchina remota
rsync
rsync -P rsync://rsync.server.com/target/file file Ottieni le differenze
rsync –bwlimit=1000 fromfile tofile Copia localmente fissando un limite del trasferimento. Ottimo per le operazioni di I/O
rsync -az -e ssh –delete ~/public_html/ remote.com:’~/public_html’ Effettua un mirron di un sito web (usa compressione e crittazione)
rsync -auz -e ssh remote:/dir/ . && rsync -auz -e ssh . remote:/dir/ Sincronizza la directory corrente con una remota
SSH
ssh $USER@$HOST command Esegui il comando command su $HOST come $USER (default command=shell)
ssh -f -Y $USER@$HOSTNAME xeyes Esegui un comando grafico (GUI) su $HOSTNAME come $USER
scp -p -r $USER@$HOST: file dir/ Copia preservando i permessi dalla home di $USER su $HOST in dir/
ssh -g -L 8080:localhost:80 root@$HOST Crea un tunnel SSH sulla porta locale 8080 verso la porta 80 remota
ssh -R 1434:imap:143 root@$HOST Crea un reverse tunnel SSH sulla porta locale 1434 verso la porta 143 remota
ssh-copy-id $USER@$HOST Installa la chiave pubblica di $USER su $HOST per effettuare login senza autenticazione
wget
(cd dir/ && wget -nd -pHEKk http://www.devme.it/downloadme.html) Scarica una versione navigabile della pagina nella directory corrente
wget -c http://www.devme.it/large.bin Effettua il resume di una risorsa scaricata precedentemente
wget -r -nd -np -l1 -A ‘*.jpg’ http://www.devme.it/dir/ Scarica l’insieme dei file indicati nella directory corrente
wget -q -O- http://www.devme.it/links.html | grep ‘a href’ | head Elabora l’output scaricato
echo ‘wget url’ | at 01:00 Scarica l’url alle 13 nella directory corrente
wget –limit-rate=20k url Effettua una download a bassa priorità
wget -nv –spider –force-html -i bookmarks.html Verifica i link all’interno del file
wget –mirror http://www.devme.it/ Aggiorna la copia locale di un sito web
Networking
ethtool eth0 Visualizza lo stato dell’interfaccia di rete eth0
ethtool –change eth0 autoneg off speed 100 duplex full Imposta manualmente la velocità dell’interfaccia di rete
iwconfig eth1 Visualizza lo stato dell’interfaccia wireless eth1
iwconfig eth1 rate 1Mb/s fixed Imposta manualmente la velocità dell’interfaccia di rete wireless
iwlist scan Elenca le reti wireless trovate
ip link show Visualizza l’elenco delle interfacce di rete
ip link set dev eth0 name wan Rinomia l’interfaccia eth0 in wan
ip link set dev eth0 up Attiva/Disattiva(down) l’interfaccia di rete
ip addr show Elenca gli indirizzi delle interfacce di rete
ip addr add 1.2.3.4/24 brd + dev eth0 Aggiunge o elimina (del) ip e la maschera (255.255.255.0)
ip route show Elenca la tabella di routing
ip route add default via 1.2.3.4 Imposta il default gateway
host www.devme.it Interroga il DNS per ottenere l’ip del dominio
hostname -i Ottiene l’indirizzo ip locale
whois pixelbeat.org Interroga il whois per ottenere le informazioni sull’hostname o l’indirizzo ip
netstat -tupl Elenca i servizi attivi sul sistema
netstat -tup Elenca le connessioni attive da/sul sistema

Stay tuned!

Mappa dei click sul proprio sito

clickNon so voi, ma diverse volte mi sono chiesto quali sono i punti in cui l’utente effettuasse i click su un sito, in particolare sul mio blog. Sono varie le considerazioni che si possono fare da un’analisi del genere, ad esempio capire quali sono gli elementi più cliccati, se un elemento posto in un certo punto della pagina ha più appeal rispetto ad un altro punto, etc etc. In generale queste mappe mostrano i punti caldi di una pagina web per i quali può essere fatta una serie di analisi. Ciò detto passiamo alla pratica. Cercando un po in rete ho trovato una soluzione open-source che voglio condividere. La soluzione usa javascript per il rilevamento dei click e perl per la costruzione della mappa. Sarebbe interessante tradurre lo script in perl in un altro linguaggio, php o Java ad esempio, così da cambiarne il contesto. Ma procediamo per gradi.

Javascript

Non mi soffermerò molto sul codice javascript che realizza la rilevazione dei click, con l’utilizzo di jquery diventa veramente semplice scrivere 2 righe di codice (si fa per dire), dopo che il DOM si è reso disponibile (document.ready()), si aggancia all’evento onclick e registra le coordinate in cui è avvenuto il click assieme ad altri dati aggiuntivi. Supponiamo quindi che i dati rilevati siano:

x709y351
x350y348
x489y294
x655y346
x384y305
x332y288
x399y288

In questo modo è possibile rilevare le zone della pagina in cui sono avvenuti più click e associare loro dei valori di intensità tali da rappresentarli correttamente sulla mappa finale. A tal proposito assegnamo come valore di intensità massima 255 e come valore di intensità minima 0.

Perl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/perl
use strict;
my $imgWidth=64;
open (LOG,"log.txt") || die;
my @log=<LOG>;
close (LOG);
my (@x,@y);
my ($xMax,$yMax,$repetitionsMax,$i,$j);
my %repetitions;
foreach my $line(@log){
	(my $coords)=$line;
	$repetitions{$coords}++;
	$coords=~s/x//;
	($x[$i],$y[$i])=split("y",$coords);
	$i++;
}
while ((my $key, my $value)=each(%repetitions)){
	$repetitionsMax=$value if $repetitionsMax<$value;
}
for ($j=0;$j<$i;$j++){
	$xMax=$x[$j] if $xMax<$x[$j];
	$yMax=$y[$j] if $yMax<$y[$j];
}
print $repetitionsMax,"\n$xMax;$yMax\n";

Analizziamo il codice di sopra. Dal file di log contenente le rilevazioni sui click effettuati, vengono lette le coordinate e salvate all’interno di due array $x e $y rispettivamente. Per ciascun valore acquisito viene determinato il valore massimo assoluto e il valore massimo della x e della y. Successivamente si procede con la creazione dell’immagine: 

my $xCanvas=$xMax+int($imgWidth/2);
my $yCanvas=$yMax+int($imgWidth/2);
my $createcanvas="convert -size ". $xCanvas.#//
"x".$yCanvas." pattern:gray100 empty.png";
system ($createcanvas);

impostando le dimensioni calcolate nello step precedente e sfruttando una funzionalità di sistema.
Dopo aver creato l’immagine procediamo col disegnare i punti della nostra mappa, anzi, invece di limitarci a disegnare dei singoli punti, andiamo a creare delle regioni a partire da un file png che ci consente di farlo. Scegliamo come valore di opacità 1 e calcoliamo una formula che ci consenta di determinare il livello di sovrapposizione (overlay) da usare per ciascuna regione. In questo modo le regioni più cliccate saranno sovrapposte e quindi più scure.

my $createNormalizedSpot="convert bolilla.png -fill #//
white -colorize ".int(100/$repetitionsMax)."% bol.png";
system ($createNormalizedSpot);
 
/* Procediamo per ciascuna riga di coordinata */
 
for ($j=0;$j<$i;$j++){
    my ($x,$y);
    $x=$x[$j]-32;
    $y=$y[$j]-32;
    system ("composite -compose multiply -geometry #//
    +$x+$y bol.png empty.png empty.png\n");
    print "used $j of $i clicks\n";
}

Otteniamo quindi un’immagine del genere:

 

empty_p

 

Come piccolo tocco di classe, rendiamo l’immagine creata, in modo tale che abbia il tipico schema di colore delle mappe di calore, in cui i punti più cliccati saranni quelli più caldi e quelli meno cliccati più freddi. Per fare questo usiamo la libreria di Imagemagick, a partire da un file di immagine contenente il gradiente del colore in questione:

convert empty.png -negate full.png
convert full.png colors.png -fx "v.p{0,u*v.h}" final.png

ottenenedo come risultato:

 

map_p

 

La mappa finale

Bene, come risultato finale, prendiamo un’immagine del nostro sito web, ottenuto attraverso uno screenshot di sistema o qualunque altra cosa adatta a farlo e sovrapponiamo la mappa creata con il seguente comando:

composite -blend 40% final.png blog.png heatmap.png

heatmap

E’ facile notare che, guardare l’immagine del risultato fa totalmente un’altro effetto rispetto al piatto file di log da cui siamo partiti.
Stay tuned !!

Linux Kernel Module – A [little] programming guide

penguinVolete scrivere un modulo per il kernel di linux ? Conoscete il linguaggio C ? Benissimo, allora armatevi e partite. Considerate questa piccola guida, un punto di partenza per la creazione di un piccolo modulo per il kernel di linux.
Prima di partire cerchiamo di capire cos’è un modulo del kernel. I moduli in generale sono dei piccoli programmi che possono essere montati e smontati run-time dal kernel ogni qual volta si presenta la necessità. Ad esempio un modulo potrebbe essere quello per un dispositivo hardware, stiamo parlando quindi di un driver di dispositivo, il quale dopo essere stato caricato permetterà l’utilizzo del dispositivo stesso. I moduli quindi estendono la funzionalità del kernel senza necessità che si effettui un reboot del sistema.
Senza moduli si avrebbero i cosiddetti kernel monolitici, ovvero blocchi di kernel che inglobano tutte le funzionalità le quali verrebberò caricate tutte assieme al momento del boot del sistema.

In linux per elencare la lista dei moduli caricati dal kernel è sufficiente eseguire il seguente comando: 
 

mulp@devme-station:~$ lsmod
Module                  Size  Used by
binfmt_misc             7960  1 
snd_hda_codec_analog    78702  1 
snd_hda_intel          25677  3 
snd_hda_codec          85759  2 snd_hda_codec_analog,snd_hda_intel
snd_hwdep               6924  1 snd_hda_codec
snd_pcm_oss            41394  0 
........
........

Sopra vediamo un esempio di lista dei moduli caricati attualmente dal kernel sulla mia macchina.

Ma come vengono caricati i moduli all’interno del kernel ? Quando il kernel ha bisogno di una funzionalità che non è stata finora caricata, si rifà al demone kmod il quale esegue il comando modprobe che si occupa del caricamento. modprobe seleziona il modulo da caricare indicandone il nome oppure un identificatore generico:

  • nome del modulo: devme-driver
  • identificativo generico: char-major-10-20

Nel caso dell’identificatore generico viene consultato il file /etc/modules.conf all’interno del quale sono definiti gli alias per ogni modulo, in questo caso dato l’identificativo precedente, il kernel farà riferimento al modulo chiamato devme-driver.o. Successivamente viene consultato il file /lib/modules/version/modules.dep per verificare se il modulo ha delle dipendenze rispetto ad altri moduli, e nel caso in cui li abbia, vengono caricate prima del modulo stesso. Questo file è creato attraverso il comando depmod -a.  Un esempio chiarificatore è dato dalla dipendenza del modulo msdos.o dal modulo fat.o, in questo caso la sequenza del caricamento sarà:

mulp@devme-station:~$ insmod /lib/modules/2.5.1/kernel/fs/fat/fat.o
mulp@devme-station:~$ insmod /lib/modules/2.5.1/kernel/fs/msdos/msdos.o

oppure

mulp@devme-station:~$ modprobe -a msdos

Passiamo quindi ad un piccolo esempio pratico di scrittura del nostro modulo. Ovviamente si tratta di un modulo esemplificativo che illustra come fare a scriverne degli altri molto più complessi, il nostro si limiterà ad illustrare i passi da svolgere per arrivare alla creazione. Quello che segue quindi è il più semplice modulo del kernel possibile: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 *  devme-module-t1.c - Il pi&ugrave; semplice modulo
 **/
#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>  /* Needed for KERN_ALERT */
 
 
int init_module(void) {
   printk("<1>Hello, I'm DevMe Kernel Module.\n");
 
   // A non 0 return means init_module failed; module can't be loaded.
   return 0;
}
 
 
void cleanup_module(void) {
  printk(KERN_ALERT "It was a pleasure work with U.\n");
}

Il codice di sopra è molto semplice e di facile comprensione. Come potete vedere ci sono alcuni metodi che devono essere implementati affinché il modulo possa essere creato correttamente. L’unica cosa degna di nota è l’utilizzo della funzione printk che non stampa nulla in output come potrebbe suggerire, ma è un meccanismo di loggin per il kernel. Il numero indicato tra parentesi acute rappresenta la priorità del log. Nel file linux/kernel.h sono elencate le varie priorità.

Affinché il modulo possa essere caricato è necessario compilarlo (ho scoperto l’acqua calda eh! :P ) , procediamo quindi con la creazione del nostro Makefile il quale renderà la procedura di installazione più pratica. Da precisare che con i kernel della serie 2.6 la procedura di compilazione dei kernel è leggermente cambiata, i moduli hanno estensione .ko e non .o come per la precedente serie 2.4. Anche la sintassi del Makefile è cambiata, ci sono alcune MACRO diverse da indicare durante la compilazione. Vediamo l’esempio che segue: 

1
2
3
4
5
6
obj-m += devme-module-t1.o
KVERSION = $(shell uname -r)
all:
	make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean

otteniamo quindi:

mulp@devme-station:~$ make
make -C /lib/modules/2.6.32-24-generic/build M=/home/mulp/blog/kernel modules
make[1]: ingresso nella directory &laquo;/usr/src/linux-headers-2.6.32-24-generic&raquo;
  CC [M]  /home/mulp/blog/kernel/devme-module-t1.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/mulp/blog/kernel/devme-module-t1.mod.o
  LD [M]  /home/mulp/blog/kernel/devme-module-t1.ko
make[1]: uscita dalla directory &laquo;/usr/src/linux-headers-2.6.32-24-generic&raquo;
 
mulp@devme-station:~$ modinfo devme-module-t1.ko 
filename:       devme-module-t1.ko
srcversion:     C8EB2BC02FE416B3877C877
depends:        
vermagic:       2.6.32.15+drm33.5 SMP mod_unload modversions

Non rimane quindi che inserire il modulo all’intero del kernel e vedere cosa succede. Eseguiamo il comando bash:

mulp@devme-station:~$ insmod devme-module-t1.ko

Tutti i moduli caricati all’interno del kernel sono presenti all’interno di /proc/modules, se non credete andate a fare cat di quel file e troverete il modulo appena inserito al suo interno. Dopo aver provato l’emozione della creazione di un modulo del kernel, procedete alla sua rimozione con il comando:

mulp@devme-station:~$ rmmod devme-module-t1

e andate a vedere nei file kern.log e syslog….troverete i log indicati nel file sorgente del modulo. L’esempio di scrittura di questo modulo è puramente didattico, la logica è praticamente inesistente ed esistono altri modi di ottimizzare le chiamate di init e cleanup di un modulo. Nei prossimi vedremo qualche altro esempio più complesso.

Stay tuned !

SWF: Model Data Binding

spring-webflowNell’ultimo articolo su Spring Web Flow ho condensato la maggior parte dei concetti chiave sull’argomento. Mi piacerebbe ora tornare indietro su alcune cose cercando di porre maggiore attenzione. In questo articolo vedremo un pò più da vicino come avviene il binding dei dati in SWF, da un form HTML verso un bean.
In SWF esiste un controller, dello stesso genere di quelli utilizzati in Spring MVC (es. AbstractFormController), che permette di effettuare il binding dei parametri corrispondenti ai campi di un form HTML, quindi presente nella request HTTP verso un command object rappresentato da una semplicissima classe Java Bean. Ad una certa view è associato un certo model object sul quale verranno memorizzati i valori dei parametri del form e affinché avvenga in binding è sufficiente dichiarare l’attributo model dell’elemento <view-state>. L’esempio che segue mostra come deve essere definito il tutto nel contesto SWF affinché avvenga correttamente il binding.

Si comincia col definire la classe del nostro Java Bean, suppioniamo di voler memorizzare le informazioni riguardanti i voli in partenza da un certo aeroporto.

package it.devme.flight;
 
import java.io.Serializable;
import java.sql.Time;
 
public class Flight implements Serializable {
 
        private static final long serialVersionUID = 1L;
 
        private String number;
        private Time time;
	private String gate;
	private boolean isDelayed;
 
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public Time getTime() {
		return time;
	}
	public void setTime(Time time) {
		this.time = time;
	}
	public String getGate() {
		return gate;
	}
	public void setGate(String gate) {
		this.gate = gate;
	}
	public boolean isDelayed() {
		return isDelayed;
	}
	public void setDelayed(boolean isDelayed) {
		this.isDelayed = isDelayed;
	}
 
}

Fin qui niente di più semplice. Procediamo ora con il nostro flow. Il flow consiste di 2 view. La prima pagina raccoglie i dati che verranno memorizzati all’interno dei 4 attributi della classe Flight. Avanzando con il bottone next, la seconda pagina semplicemente mostrerà i dati raccolti.

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
 
    <var name="flight" class="it.devme.flight.Flight" />
 
    <view-state id="start" view="flight/insertFlightInfo" model="flight">
      <transition on="next" to="confirm" />
    </view-state>
 
    <view-state id="confirm" view="flight/showFlightInfo" />
 
</flow>

All’inizio del flow creiamo la variabile di flow flight la quale è un istanza della classe Flight. Fissando questa variabile come attributo model nella start view, diciamo a SWF di utilizzare questo oggetto per effettuare il binding dei dati. Implementando una semplicissima pagina HTML con un form chiudiamo il primo cerchio.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
 
<html>
  <head>
    <title>DevMe - SWF Flight info test - </title>
  </head>
 
<body>
  <h1>Flight information </h1>
  <p>Inserisci le informazioni sul volo:</p>
    <form:form id="flightDetails" modelAttribute="flight">
      <table>
        <tr>
          <td>Numero del volo: </td>
         <td><form:input path="number"/></td>
        </tr>
 
        <tr>
          <td>Ora di partenza: </td>
          <td><form:input path="time"/></td>
        </tr>
 
        <tr>
         <td>Gate: </td>
         <td><form:input path="gate"/></td>
        </tr>
 
        <tr>
          <td>Volo in ritardo: </td>
          <td><form:radiobutton path="isDelayed" value="false" />
  	      <form:radiobutton path="isDelayed" value="true" /></td>
        </tr>
 
        <tr>
          <td><input type="submit" name="_eventId" value="next"></td>
        </tr>
    </table>
    </form:form>
  </body>
</html>

Cliccando sul Next ci spostiamo verso la seconda view definita all’interno del flow attraverso la transition confirm. All’interno di questa transition i valori dei campi del form vengono inviati in POST e automaticamente ne viene fatto il bind verso l’oggetto flight presente nel flow scope. Successivamente, durante il caricamento della view confirm, vengono eseguite le espressioni EL rispetto al valore dei campi del bean, consentendoci quindi di visualizzarne il valore.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
 
<html>
  <head>
    <title>Flight Information Details</title>
  </head>
 
<body>
 
  <h1>Flight Information Details</h1>
  <p>Dettagli del volo:</p>
  <form:form modelAttribute="flight" >
 
    <table>
      <tr>
        <td>Numero volo: </td>
        <td>${flight.number}</td>
      </tr>
 
      <tr>
       <td>Orario: </td>
       <td>${flight.time}</td>
      </tr>
 
      <tr>
       <td>Gate: </td>
       <td>${flight.gate}</td>
      </tr>
 
      <tr>
       <td>Ritardo: </td>
       <td>${flight.isDelayed}</td>
      </tr>
 
   </table>
 </form:form>
</body>
</html>

Come vedete è molto semplice. Una piccola nota: se per qualunque ragione non si volesse proseguire durante una transition, al binding dei parametri della request è sufficiente aggiungere l’attributo bind all’interno del tag transition indicando come valore false.

    <view-state id="start" view="flight/insertFlightInfo" model="flight">
      <transition on="next" to="confirm" />
      <transition on="cancel" to="end" bind="false" />
    </view-state>

Nel prossimo articolo parleremo della validazione dei campi di un form. Alla prossima
Stay tuned!

 

You need to log in to vote

The blog owner requires users to be logged in to be able to vote for this post.

Alternatively, if you do not have an account yet you can create one here.

Powered by Vote It Up

WordPress Themes