lunedì 23 gennaio 2012

Jpa annotation su properties oppure fields

Secondo le specifiche EJB 3.0 è possibile avere le annotation sui campi delle Entity class oppure sulle property che fungono da accessor per tali campi.
E' importante notare che il consiglio dato dalla specifica è utilizzare nella stessa entità o le annotation sui fields oppure sulle properties, mixando le due cose si possono avere dei problemi e non è garantito il funzionamento su tutte le implementazioni di JPA.
La spiegazione su quale approccio sia meglio usare è oggetto di varie discussione.
Qui si può trovare un post interessante in merito.

domenica 22 gennaio 2012

Come ottenere un'istanza di un EntityManager

L'interfaccia javax.persistence.EntityManager, che consente di operare modifiche sul database ed è definito sul testo "EJB in ACTION" "the bridge between the OO and relational word", può essere ottenuta in due modi:
  • Tramite l'annotation @PersistenceContext come variabile di classe, ed in tal caso si parla di "container manager EntityManager";
  • Tramite l'interfaccia javax.persistence.EntityManagerFactory, ed in questo caso si parla di "application manager EntityManager".
Nel primo caso tutto è gestito dal container. Bisogna avere l'accortezza di evitare di utilizzare questo tipo di injection direttamente come variabile di istanza di una servlet, non essendo quest'ultima thread safe per definizione (a meno di implementare l'interfaccia SingleThreadModel).

Nel secondo caso bisogna scrivere il codice per controllare ogni aspetto del ciclo di vita dell' EntityManager, inizializzandolo nel @PostConstruct e chiudendolo nel @PreDestroy, mentre per ottenere l'EntityManagerFactory si utilizza l'annotation @PersistenceUnit

Di seguito un esempio di utilizzo:

@Stateless
public class ItemManagerBean implements ItemManager {

@PersistenceUnit
private EntityManagerFactory emF;
private EntityManager entityManager;
public EntityManager(){
}
@PostConstruct
public void initialize(){
entityManager=emF.createEntityManager();
}
..... metodi di business in cui si utilizza l'EntityManager

@PreDestroy
public void cleanUp(){
if(entityManager.isOpen()){
entytyManager.close();
}
}

}

sabato 21 gennaio 2012

Javascript funzione setTimeout

La funzione setTimeout in Javascript consente di eseguire un determinato codice javascript con un intervallo specificato in millisecondi.
Vediamo un esempio, preso dalla sezione tips and tricks della rivista Io Programmo di questo mese.
Abbiamo una semplice casella di testo e un bottone, quando premiamo il bottone quello che abbiamo scritto sarà cancellato carattere per carattere con un intervallo di mezzo secondo tra un carattere e l'altro, simulando la cancellazione manuale.
Il codice del metodo js è il seguente:

function deleteChar(t){
var testo=document.getElementById(t);

var inside=testo.value;

if(inside){
      
    testo.value=inside.substring(0,inside.length-1);
        setTimeout("deleteChar("+"'"+t+"'"+")",500);
}
}

Vediamolo all'opera:


Scrivi testo:

Optimistic Locking

Quando si realizzano applicazioni con un altro grado di concorrenzialità bisogna curare particolarmente gli aspetti relativi ai lock sul db.
In un sistema concorrenziale sono possibili 3 tipi di problemi:
  • Dirty Read : Un utente può leggere dati modificati e non ancora committati da altre transazioni, dati che quindi non è detto che debbano poi essere persistiti.
  • Nonrepeatable read : L'utente può leggere e modificare i dati non ancora committati, ad esempio l'entità USER prende l'entità ITEM, che è in gestione da parte di una transazione X che alla fine cancella ITEM. A questo punto USER ha ancora la copia dell'entità ITEM originale e può modificarla ma chiaramente andando a persistere il tutto su DB si incapperà in errori apparentemente inspiegabili;
  • Phantom read: accade quando l'utente nel corso della stessa transazione va a leggere per due volte un'entità e trova che la seconda volta i valori sono cambiati rispetto alla prima, poichè nel frattemo un'altra transazione ha modificato gli stessi
I livelli di isolamento tipicamente gestiti dai moderni DBMS sono i seguenti (ordinati dal piu basso livello di isolamento al più alto):

  • READ UNCOMMITTED: La transazione può leggere dati non committati di altre transazioni. Questo livello di isolamento porta inevitabilmente al rischio di DIRTY READ;
  • READ COMMITTED: La transazione può leggere soltanto dati committati, questo è il livello base per molti DBMS;
  • REPEATABLE READ: Con questo livello di isolamento si garantisce che nel corso della transazione qualora si acceda più volte allo stesso oggetto i valori restituiti saranno sempre gli stessi, per evitare il problema del Phantom Read;
  • SERIALIZABLE: E' il livello più alto di isolamento e garantisce che nessuna delle tabelle interessate dalla transazione sarà modificata da altri utenti. In questo modo chiaramente le performance dell'applicazione ne risentono molto.
Le strategie utilizzate per affrontare i problemi di concorrenzialità con gli EJB e JPA sono di 2 tipi:
  • Pessimistic Locking;
  • Optimistic Locking.
Il Pessimistic Locking parte dal presupposto che bisogna assolutamente impedire che si verifichino problemi di concorrenzialità per cui si lockano tutte le tabelle coinvolte nel database. JPA non provvede supporto per questa strategia, sebbene alcuni persistence provider abbiano estensioni proprietarie per gestirla.

L'Optimistic Locking invece è una strategia che parte dal presupposto che i problemi di concorrenzialità siano minimi e che sia quindi meglio risolverli quando accadono piuttosto che ingessare troppo il sistema.

L'implementazione dell'optimistic locking si basa sul fatto che quando un utente ottiene un oggetto dal db in realtà lavora su una copia dello stesso e poi al momento della persistenza dell'oggetto sul db il sistema rileva se nel frattempo quell'oggetto è stato modificato ed in tal caso torna un errore da gestire.
Per realizzare questa strategia si aggiungono alle tabelle interessate delle colonne di tipo version che possono essere interi o timestamp.

Vediamo un esempio:

@Entity
@Table("PERSONA")
public class Persona implements Serializable
@Id
@Column(name="ID_PERSONA")
protected long idPersona;
.......
@Version
@Column(name="VERSION")
private Long version;

......

Il campo version non può essere gestito dall'applicazione ma è modificato soltanto dal persistence provider.
Se all'atto dell'insert/update/delete dell'entità il sistema verifica un diverso valore del campo version torna all'utente una eccezione di tipo
javax.persistence.OptimisticLockException, una RuntimeException.

E' possibile con JPA anche gestire manualmente il lock, in questo modo:

entityManager.lock(object,LockModeType.READ)

Se si prova a chiamare il lock su un oggetto senza un campo annotato come Version il sistema torna una javax.persistence.PersistenceException (runtime Exception ed eccezione padre della OptimisticLockException).
LockModeType è un Enum che può assumere valori:
  • READ per ottenere un lock in lettura;
  • WRITE per impedire a chiunque altro di agire sull'entità, qualora altre transazioni accedessero otterrebbero una OptimisticLockException.


venerdì 20 gennaio 2012

Impedance mismatch

Con il termine "impedance mismatch" si intendono le differenze di adattamento di un modello ad oggetti con il classico sistema relazionale di archiviazione dati.
Concetti come l'ereditarietà ad esempio, basilari nella programmazione ad oggetti, non sono presenti in un modello relazionale.
Con JPA sono possibili 3 strategie di "inheritance mapping", le descriviamo prendendo come un esempio la seguente gerarchia di classi volutamente semplificata:

public class Persona{
 public String nome;
public String cognome;
}


public class Studente extends Persona{
 public String matricola;
public int annoCorso;
}

public class Professore extends Persona{
public String materiaInsegnata;
}
  1. SINGLE TABLE (strategia di default per gli EJB 3.0)
  2. JOINED TABLES
  3. TABLE PER CLASS
SINGLE TABLE

Con questa strategia tutte le classi della scala gerarchica sono mappate ad un'unica tabella, che conterrà quindi l'insieme di tutti i dati e che chiameremo PERSONE.
Gli oggetti differenti sono individuati tramite una colonna di discriminazione, ad esempio nella nostra tabella potremo definirla TIPO_PERSONA char(1) e mapparla con il valore S se  Studente e P se professore.
Il modello di entità coinvolte sarà quindi di questo tipo:

@Entity
@Table(name="PERSONE")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TIPO_PERSONA",discriminatorType=DiscriminatorType.STRING,lenght=1)
public abstract class Persona{
.....
}


@Entity
@DiscriminatorValue(value="S")
public class Studente extends Persona{
....
}

@Entity
@DiscriminatorValue(value="P")
public class Professore extends Persona{
....
}

Si noti che la strategia viene mappata nella classe radice dell'albero gerarchico.
Il grosso svantaggio di questo approccio è il mancato sfruttamento delle potenzialità del database.


JOINED-TABLES

Con questo modello si sfruttano le potenzialità del dbms, inserendo i campi comuni in una tabella e legando le tabelle professore e studente con una relazione uno a uno.
Avremo quindi una struttura di questo tipo

Tabella Persona

ID_PERSONA(PK)
NOME
COGNOME
TIPO_PERSONA

Tabella Studente
ID_PERSONA(PK)
...(campi specifici)

Tabella Professore
ID_PERSONA(PK)
...(campi specifici)


Anche in questo caso è necessario avere il campo discriminatore, la struttura ad oggetti sarà la seguente (in grassetto le differenze rispetto al precedente esempio)



@Entity
@Table(name="PERSONE")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="TIPO_PERSONA",discriminatorType=DiscriminatorType.STRING,lenght=1)
public abstract class Persona{
.....
}


@Entity
@DiscriminatorValue(value="S")
@PrimaryKeyJoinColumn(name="ID_PERSONA")
public class Studente extends Persona{
....
}


@Entity

@DiscriminatorValue(value="P")
@PrimaryKeyJoinColumn(name="ID_PERSONA") 

public class Professore extends Persona{

....

}

Da un punto di vista del design questa scelta è sicuramente più elegante e generalmente consigliata.


TABLE-PER-CLASS

Con questa strategia sia la superclasse sia le sottoclassi hanno le loro tabelle di riferimento e non esistono relazioni tra le tabelle stesse.
In pratica le relazioni esistono solo sul modello ad oggetti mentre le tre tabelle lato DMBS non sono correlate. E' tuttavia molto più complicato eseguire query sugli oggetti e spesso bisogna ricorrere alle UNION, non molto efficienti.
Lato Java la situazione è la seguente:


@Entity

@Table(name="PERSONE")

@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

public  class Persona{

.....

}





@Entity
 @Table(name="STUDENTE")

public class Studente extends Persona{

....

}



@Entity

@Table(name="PROFESSORE")

public class Professore extends Persona{

....

}

Questa strategia è la più confusionaria delle 3 e proprio per questo motivo per gli AS non è obbligatorio implementarla 

lunedì 16 gennaio 2012

Comportamento oggetti passati come parametro ad Ejb Remoti

Java è un linguaggio dove gli oggetti sono passati byReference.
Negli Ejb Remoti tuttavia quando passiamo un oggetto al server è passato soltanto lo stato, non l'oggetto stesso, quindi questa regola del pass by reference non vale.
Esempio:

Interfaccia Remota

@Remote
public interface RemoteInt {

    public void manipulate(Data d);
}


Implementazione

import javax.ejb.Stateless;

@Stateless
public class RemoteImpl implements RemoteInt {

    @Override
    public void manipulate(Data d) {
               d.setAmount(100);
    }

}


Ora richiamandolo in questo modo da un client Java :

Properties p=new Properties(); 
 p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
 p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); 

 p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099"); 
Context context = new InitialContext(p); 
RemoteInt sr=(RemoteInt)context.lookup("RemoteImpl/remote"); 
Data d=new Data(); 
d.setAmount(10);
 sr.manipulate(d);
  System.out.println(d.getAmount());


Otterremo il risultato di avere in output dalla System.out il valore 10 e non , come sarebbe stato nel caso di un qualsiasi metodo Java normalmente chiamato, 100.

mercoledì 11 gennaio 2012

Java stampare il printscreen del pc su file

Per eseguire questa operazione (il classico tasto STAMP sul pc) si può utilizzare la libreria java.awt.

In questa classe vediamo un semplice esempio di realizzazione di 2 printscreen , uno limitato da noi via codice e un altro con lo schermo intero.
I 2 printscreen sono poi persisititi su un file immagine con estensione png,.

import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class PrintScreen {

    public static void main(String[] args) {
   
        try {
            Robot robot = new Robot();
            // Cattura una parte dello schermo
            int x = 100;
            int y = 100;
            int width = 200;
            int height = 200;
            Rectangle area = new Rectangle(x, y, width, height);
            BufferedImage bufferedImage = robot.createScreenCapture(area);
            saveImage("AreaPiccola.png", "png", bufferedImage);
            // Cattura l’intera area dello schermo
            area = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
            bufferedImage = robot.createScreenCapture(area);
            saveImage("SchermoIntero.png", "png", bufferedImage);

            }
            catch (Exception e)
            {
                e.printStackTrace();
            }

    }
    public static void saveImage(String nomeFile,String estensione,BufferedImage bufferedImage) throws Exception
    {
         File outputfile = new File(nomeFile);
         ImageIO.write(bufferedImage,estensione, outputfile);
    }
}