Posts tagged: java

Spring Web Flow tutto d’un fiato ! [Part 2/2]

spring-webflowRieccoci qui per continuare il discorso iniziato nel post precedente su SFW, il framework per la creazione di applicazioni web. Dopo aver definito gli elementi facenti parte della definizione di un flusso (flow) vediamo come è possibile definirlo, attraverso la sua specifica XML. Come detto in precedenza, il flow ha inizio grazie al flow executor un componente interno di SWF. L’executor da inizio al flow a partire dallo stato configurato come attributo nel tag root della definizione del flow:

<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"
      start-start="loginState">
	<-- Add your definition here -->
</flow>

loginState rappresenta lo stato iniziale da cui avrà inizio l’esecuzione del flow. Come già detto gli stati sono gli elementi di base della definizione di un flow, in cui è possibile transire da uno stato ad un’altro effettuando delle operazioni, dei controlli o visualizzare dell’output. Tra i possibili stati che possono essere utilizzati vi è il View State, il quale viene utilizzato per visualizzare o chiedere informazioni agli utenti. Una view può essere una qualunque pagina JSP, ma può anche essere una qualunque view supportata da Spring MVC. Di seguito viene riassunto l’elenco di possibili elementi figli del view state:

  • <attribute>, dichiara un attributo che descrive lo stato.
  • <binder>, usato per configurare un custom form binding.
  • <exception-handler>, riferisce un bean che implementa un FlowExecutionExceptionHandler che gestisce tutte le eccezioni sollevate nello stato corrente.
  • <on-entry>, indica quali azioni devono essere eseguiti quando si entra in questo stato.
  • <on-exit>,  indica quali azioni devono essere eseguiti quando si esce da questo stato.
  • <on-render>. indica quali azioni devono essere eseguiti quando si visualizza questo stato.
  • <secured>, viene utilizzato assieme a Spring Security per restringere l’accesso a questo stato.
  • <transition>, definisce un percorso da questo stato ad un’altro basato sul verificarsi di un evento o un’eccezione.
  • <var>, dichiara una variabile.

Ciò detto, il modo più semplice per dichiarare un View State è il seguente:

<view-state id="login"/>

Il tag di sopra definisce una view logica, ovvero non associata a nessuna pagina fisica, da cui non sarà possibile transire in nessun’altro stato. Per associare la view, il nome logico definito dall’attributo id ad una pagina jsp è necessario aggiungere l’attributo view,

<view-state id="login" view="loginForm"/>

in questo modo la view è associata alla pagina loginForm.jsp, la quale verrà visualizzata al caricamento della view. Nota: sarà possibile evitare di dover specificare l’estensione dei file associati alle view, configurando opportunamente Spring MVC View Resolver.

Ma vediamo un’esempio un pò più completo:

<view-state id="login" view="loginForm">
  <transition on="accountEntered" to="homeUser" />
  <transition to="endState" on="cancel" />
</view-state>

l’esempio di sopra definisce due elementi figli del tag view, elementi transition. Il primo dei due indica una transizione dallo stato corrente allo stato homeUser, al verificarsi incondizionato dell’evento accountEntered. Il secondo definisce una transizione dallo stato corrente allo stato endState al verificarsi dell’evento cancel. Come definiamo questo tipo di eventi ? Molto semplicemente….lo scatenarsi degli eventi avviene direttamente dalle view fisiche associate. Consideriamo la view loginForm.jsp associata alla view logica login come segue:

<form:form>
   <!-- HTML form definition here -->
   <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/>
   <input type="submit" name="_eventId_accountEntered" value="Entra" />
   <input type="submit" name="_eventId_cancel" value="Annulla" />
</form:form>

la pagina web contiene tra gli altri elementi che ospiteranno i dati di accesso dell’utente, il pulsante di submit della pagina e un campo hidden. Quest’ultimo è richiesto per riconoscere l’id del flow in cui ci si trova ed è sempre necessario. I pulsanti di submit, oltre al loro classico funzionamento servono anche a scatenare gli eventi che abbiamo definito nel file di flow. Si noti il nome del pulsante submit Entra che invia i dati del form al server e serve per effettuare l’autenticazione dell’utente. In particolare il nome del pulsante ha un prefisso _eventId_ il quale indica a SWF che alla pressione del bottone dovrà scatenare un evento il cui nome è ciò che segue il prefisso, nel nostro caso accountEntered. In questo modo è possibile catturare l’evento nel file di definizione del flow. Stesso discorso vale per il bottone cancel.
E’ possibile anche scatenare un’evento attraverso un link, ad esempio:

<a href="${flowExecutionUrl}&_eventId=accountEntered">Entra</a>

Altro modo consiste nel creare un acampo hidden all’interno del form con name _eventId.

Dopo aver analizzato il ViewState che permette all’utente di essere coinvolto all’interno del flow, passiamo a vedere l’ActionState il quale definisce alcuni elementi che permettono di effettuare delle elaborazioni all’interno del flow. L’elenco dei nodi figli dell’action state è il seguente:

  • <attribute>, dichiara un attributo che descrive lo stato
  • <evaluate>, valuta un’espressione assegnando opzionalmente il risultato.
  • <exception-handler>, referenzia un bean che implementa FlowExecutionExceptionHandler il quale gestisce le eventuali eccezioni per lo stato corrente.
  • <on-entry>, definisce un’azione la quale viene eseguita all’ingresso dello stato.
  • <on-exit>, definisce un’azione la quale viene eseguita all’uscita dello stato.
  • <render>, richiede che la prossima view renderizzi un frammento di contenuto.
  • <secured>, restringe l’accesso allo stato corrente richiedendo l’inserimento degli attributi utente.
  • <set>, imposta una variabile all’interno dello scope del flow.
  • <transition>, definisce una transizione verso uno stato al verificarsi di un evento. Lo stato di destinazione può coincidere con lo stato corrente.

Quindi vediamo un’esempio d’uso dell’ActionState:

<action-state id="homePage">
	<evaluate expression="devME.authenticateUser(username, password)" />
	<transition to="home" on="userOK" />
	<transition to="loginForm" on="userKO" />
</action-state>

Il codice di sopra definisce il seguente comportamento. Dopo che l’utente ha inserito i propri dati di accesso all’interno del form e clicca sul pulsante Entra viene scatenato l’evento accountEntered, il quale prevede una transizione nello stato homeUser, un’ActionState. All’interno viene valutata un’espressione la quale esegue un metodo di autenticazione dell’utente sulla base dei dati forniti. Lo stesso metodo scatena 2 eventi diversi: userOK se l’utente è stato autenticato, dal quale si transisce verso la home dell’utente. L’evento userKO se l’utente non è stato autenticato e quindi si ritorna alla view di login. Come vedete è molto semplice e intuitivo.
Stay tuned.

Spring Web Flow tutto d’un fiato ! [Part 1/2]

spring-webflowSpring Web Flow è un framework basato su Spring MVC che permette lo sviluppo di applicazioni flow-based. In questo articolo vedremo come aggiungere Spring Web Flow ad applicazioni Spring-based e definire alcuni flussi tra le applicazioni e i loro utenti.
Iniziamo col dire che tutti i flussi (da ora in avanti li chiameremo con loro vero nome, flow) sono costituiti da 3 elementi base, ovvero:

  • States
  • Transitions
  • Flow data

States: indica ciò che accade all’interno di un flow. Spring Web Flow definisce 5 tipi di States differenti: View, Active, End, Subflow, Decision. Vedremo più avanti come questi tipi di stato partecipano alla creazione di un flow.
Transitions: sono di fatto il mezzo di collegamento tra i vari States. Una View state, può contenere al suo interno un certo numero di transizioni ciascuna delle quali collega altri stati.
Flow data: all’interno di un flow vengono collezionati alcuni dati che dipendono dagli stati in cui il flow si trova o si trovava. La visibilità dei dati di ciascun flow dipende dallo scope con cui questo viene definito. Per la precisione esistono 5 tipi di scope differenti in SWF che sono:
 

  • Flow scope : viene creato all’inizio del flow e distrutto quando il flow termina. I dati all’interno del Flow scope sono accessibili e disponibili per tutta la durata del flow
  • Conversation scope : viene creato all’inizio di un top-level flow e distrutto quanto il flow termina. Il conversation scope è simile al flow scope, eccetto per l’accesso ai dati. Infatti mentre il flow scope è accessibile solo dal flow che l’ha creato, il conversation flow può essere acceduto sia dal top-level flow che da tutti i suoi subflow.
  • Request scope : viene creato all’inizio di una richiesta HTTP e distrutto al termine di tale richiesta. I dati all’interno del request scope sono disponibili a tutti gli stati del flow per l’intera durata della richiesta.
  • Flash scope : viene creato quando il flow ha inizio, ripulito quando si entra all’interno di una view e distrutto alla fine del flow. I dati all’interno del flash scope sono disponibili a tutti gli states per l’intera durata del flow.
  • View scope : viene creato quando il flow entra all’interno di una view e distrutto quando la view viene renderizzata. E’ il flow che ha più breve durata, per questo motivo i dati all’interno di questo scope sono disponibili solo alla view che li ha creati.

Ciò detto vediamo come fare ad installare ed utilizzare SFW in pochi semplice passi. Naturalmente per poter iniziare a lavorare con SWF è necessario scaricare i jar che lo contengono, questa pagina costituisce il punto di partenza da cui potete trovare info dettagliate sul framework e dal link download potete scaricare le librerie. Le librerie necessario da aggiungere al classpath della propria applicazione sono :

  • org.springframework.WebFlow-2.0.8.RELEASE.jar
  • org.springframework.binding-2.0.8.RELEASE.jar
  • org.springframework.faces-2.0.8.RELEASE.jar
  • org.springframework.js-2.0.8.RELEASE.jar

in realtà WebFlow e Binding sono le librerie principali, mentre faces e js mettono a disposizione il supporto a JSF e Javascript/Ajax. In aggiunta a queste librerie è necessario aggiungere il supporto al linguaggio che aiuta a definire i Flow.
SWF usa OGNL.

SWF come detto si basa su Spring MVC, quindi così come per tutte le applicazioni spring-based, le richieste passano attraverso il DispatcherServlet. Per configurare SWF basta aggiungere le seguenti righe di codice al file servlet.xml :

<servlet>
    <servlet-name>DevMeApp</servlet-name>   
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

Bene, a questo punto non rimane che indicare quale richiesta debba essere "catturata" da spring e quindi girata a SWF. Per fare questo, ci basterà configurare il nostro DispatcherServlet con un handle per tutte le richieste il cui URL fa match con la stringa "devme"…tradotto:

<servlet-mapping>
  <servlet-name>DevMeApp</servlet-name>
  <url-pattern>/devme/*</url-pattern>
</servlet-mapping>

Ora che abbiamo configurato Spring passiamo alla configurazione di SWF. La configurazione avviene tramite compilazione di file XML di Spring aggiungendo a tali file il namespace di SWF, in modo tale da poter utilizzare i tag messi a disposizione dal framework. Quindi partendo da un file di spring aggiungiamo i seguenti namespace:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
</beans>

quindi aggiungiamo la nostra configurazione all’interno del tag beans.
La prima cosa da fare è aggiungere un riferimento al flow executor, ovvero all’elemento che gestisce l’esecuzione del flow. Aggiungiamo quindi il tag:

<webflow:flow-executor id="flowExecutor"/>

Il secondo step è quello di indicare a SWF dove trovare il file xml della definizione del flow. Questo viene fatto attraverso il tag flow registry che permette di indicare la posizione su file system in cui risiedono i file XML dei vari flow. Per esperienza, è molto comodo creare i file di flusso separati all’interno di ogni singolo file.
Aggiungiamo quindi il flow registry:

<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows-defs">
	<webflow:flow-location id="devme" path="/WEB-INF/flows/devme-flow.xml" />
</webflow:flow-registry>

l’attributo id del tag flow location permette di assegnare un id al flow di modo che possa essere riferito all’occorrenza. In assenza dell’attributi id, l’id del flow corrisponderà al nome del file del flow.

SWF fornisce un handler adapter (spring based) che permette che fa da bridge tra il DispatcherServlet e il flow executor, gestendo la richiesta e manipolando il flow. E’ necessario configurare l’handler all’interno del file di configurazione affinché possa essere invocato dal framework. Aggiungiamo quindi il seguente tag bean:

<bean class="org.springframework.WebFlow.mvc.servlet.FlowHandlerAdapter">
  <property name="flowExecutor" ref="flowExecutor" />
</bean>
<bean class="org.springframework.WebFlow.mvc.servlet.FlowHandlerMapping">
  <property name="flowRegistry" ref="flowRegistry" />
</bean>

in questo modo il DispatcherServlet è in grado di stabilire a chi girare la richesta consultando uno o più handler. Nel codice di sopra abbiamo aggiunto un riferimento al FlowHandlerMapping il quale mantiene un riferimento al FlowRegistry in modo tale da girare la richiesta al flow corretto. Un’applicazione basata su SWF tipicamente contiene più di un flow, per questo il collegamento tra FlowHandlerMapping e flow registry consente di selezionare il flow corretto sulla base della richiesta ricevuta.

Dopo aver configurato la nostra applicazione Spring fornendo il supporto a SWF vediamo come definire un file di flow. Un file di flow è un file XML diverso da quello visti finora, nel senso che ha un nodo radice diverso il quale appartiene ad un namespace differente.
 

<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">
	<-- Add your definition here -->
</flow>

Vediamo quali sono gli elementi che contribuiscono alla definizione di un flow. Di seguito viene mostrato un elenco di tali elementi con per ciascuno una breve descrizione.

  • <action-state>, definisce una o più azioni, al termine delle quali si può transire verso uno stato successivo all’interno del flow.
  • <attribute>, consente di definire un attributo da memorizzare all’interno del flow. Viene utilizzato assieme al tag <value>.
  • <bean-import>, importa un elemento bean definito dall’utente.
  • <decision-state>, permette di valutare un’espressione sulla base della quale decidere verso quale stato transire.
  • <end-state>, indica lo stato finale del flow. La transizione su questo stato comporta il termine del flow.
  • <exception-handler>, indica un bean che può gestire eccezioni per questo flow.
  • <global-transition>, definisce una o più transizioni che sono disponibili da tutti gli stati.
  • <input>, definisce un input per questo flow.
  • <on-end>, evento che definisce l’azione che viene richiamata quando il flow termina.
  • <on-start>, evento che definisce l’azione che viene richiamata quando il flow inizia.
  • <output>, definisce un output per questo flow.
  • <persistence-context>, crea e alloca un contesto quando il flow ha inizio. Viene usato assieme al transaction manager.
  • <secured>, viene usato per restringere l’accesso ad un determinato stato.
  • <subflow-state>, invoca un nuovo flow come sotto-flow di quello corrente.
  • <var>, definisce una variabile con flow scope.
  • <view-state>, indica uno stato che si presenta all’utente tipicamente caricando un certo output e richiedendo l’interazione da parte dell’utente.

Per evitare di dlungarmi più di quanto abbia già fatto rimando la continuazione di questo articolo al post successivo. Continuo a scrivere quandi non passerà molto dalla pubblicazione seguente…prometto :P  !
Stay tuned.

NFC: qualcosa si muove (part-two)

NFC2Seconda parte dell’articolo su come scrivere programma che legge da un tag RFC e scrive su un tag RFC. Qui potete trovare quanto scritto sulla lettura da un tag NFC.
La parte che andremo ad analizzare prevede la scrittura di alcune informazioni su un tag NFC, attraverso l’interfaccia della nostra applicazione. Nello specifico andremo a scrivere i dati di un nuovo contatto della rubrica sul tag e successivamente potremo leggere quanto scritto con la funzionalità vista nell’articolo precedente.

Anche in questo caso la logica che sta dietro alla funzionalità è basata sugli eventi, in particolare, per la classe NFCWriter viene registrato un evento, il Tag Detection, che quanto catturato, esegue il codice contenuto al suo interno. Dall’interfaccia viene richiesto di inserire il testo da scrivere sul tag, si preme su OK e si avvicina il cellulare in prossimità del tag. A quel punto viene gestito l’evento che si preoccupa di stabilire una connessione con il tag NFC ed inviare.

 

write-on-nfc-1     write-on-nfc-3

 

Vediamo il codice che realizza quanto detto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class NDEFWriter extends NDEFHandler {
    Form previousScreen = null;
    String fName = "No name";
 
    public NDEFWriter(Form form) {
	previousScreen = form;
    }	
 
    public void targetDetectionMade(TargetProperties[] tProp) {
	previousScreen.append("Target detected.\n");
	if(tProp == null || tProp.length == 0) {
	    previousScreen.append("No TargetProperties found!\n");
	}
	NDEFTagConnection ndefTagConnection = null;
	try {				
	    previousScreen.append("Target mapping:"+tProp[0].getMapping()+"\n");				
	    ndefTagConnection =NDEFUtil.getNDEFTAGConnection(tProp,previousScreen);
	    if(ndefTagConnection == null) {
		previousScreen.append("Could not establish connection to card.\n");
		return;
	    }
	    NDEFUtil.writeNDEFMessage(ndefTagConnection,previousScreen);
	    ndefTagConnection.close();
	} catch (Exception e) {
	    if(ndefTagConnection != null) {
		try {
		    ndefTagConnection.close();
		} catch (IOException e1) {
		    previousScreen.append("Exception in closing connection:"+e1.toString());
		}
	    }
	    previousScreen.append("Exception:\n"+e.toString()+"\n");
	    e.printStackTrace();
	}
 
    }
 
    public String getFormattedName() {
	return fName;
    }
 
    public void setFormattedName(String fName) {
	this.fName = fName;	
    }
}

Verifica dei dati scritti sul tag

Come potete vedere non è molto difficile realizzare un programma Java che sfrutti le potenzialità fornite dalla tecnologia NFC, tutta sta a conoscere un pò le API messe a disposizione dalla Nokia. Tutto il resto è Java, gestione degli eventi, ereditarietà, interfacce, etc etc. Un vero (buon) programmatore Java non troverà alcuna difficoltà a realizzare la maggior parte delle funzionalità.
Questo è tutto.
Il codice completo per far girare l’esempio lo trovato nelle SDK del Nokia 6131 NFC è necessario la registrazione sul sito per poter effettuare il download. Dopo di che cercate nella cartella examples.
Stay tuned. yo.
 

NFC: qualcosa si muove (part-one)

NFC2Oggi ho visto in tv un servizio che parlava su come usare il proprio cellulare per effettuare piccoli pagamenti, il cosidetto telefonino/bancomat. Il funzionamento si basa sulla tecnologia Near Field Communication, ovvero un’evoluzione dell’ RFID la tecnologia che permette di far comunicare due dispositivi portanto in prossimità l’uno dell’altro. In questo articolo pubblicato sulle pagine di devme poco tempo fa, reperibile qui si parla di questa tecnologia, in particolare è possibile utilizzare il telefonino come fosse bancomato, nella modalità touch-to-pay: "avvicinando il cellulare sarà possibile utilizzarlo come una carta di credito. Le informazioni sensibili della carta sono memorizzate al suo interno in un elemento chiamato secure element. In sostanza funziona come una carta di credito senza contatto.E’ possibile visualizzare le informazioni informative classiche delle proprie transazioni".
Nello specifico in linea di principio basta scrivere i dati del proprio bancomat all’interno del cosidetto secure element e a quel punto sarà possibile, avvicinando il cellulare in prossimità di un dispositivo capace di leggere tag NFC, effettuare un’addebito sul proprio conto corrente. Pensateci, quale migliore comodità !!
Bene, analizziamo ora più da vicino, in un esempio molto semplice, come scrivere un programma che legge da un tag NFC e scrive su un tag NFC. Il programma è scritto in Java, l’IDE che utilizziamo per fare il test è Eclipse sul quale installeremo il plugin eclipseme che permette di sviluppare applicazione utilizzando le librerie J2ME.

Partiamo quindi lo scrivere la nostra midlet, DevMeNFCMidlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class DevMeNFCMidlet extends MIDlet {
    Display display;
    MainList list;
    String[] actions = new String[]{"Read","Write","Show contacts"};
    Image[] images = null;
 
    protected void startApp() throws MIDletStateChangeException {
	display = Display.getDisplay(this);
	list = new MainList("Select action to do:", List.EXCLUSIVE,actions,images,this,null);
	display.setCurrent(list);
    }
 
    protected void pauseApp() {}
 
    public void destroyApp(boolean arg0) throws MIDletStateChangeException {
	notifyDestroyed();
    }
 
    /**
     * Helper method to change the current displayable
     * 
    */
    public void setToDisplay(Displayable dspl) {
	display.setCurrent(dspl);
    }
}

Nel caso vi foste persi qualcosa sulle Midlet Java, in breve, è un’applicazione che gira su sistemi su cui è presente la J2ME Virtual Machine. Per creare una Midlet è sufficente estendere la propria classe con la classe Midlet, messa a disposizione dal Wireless Toolkit. L’estensione impone l’implementazione di alcuni metodi dal momento che la classe Midlet è una classe astratta. Il metodo StartApp() viene richiamato al momento del lancio dell’applicazione e nel nostro caso crea una lista con 3 opzioni: Read, Write e Show Contacts. La nostra applicazione legge da un tag NFC virtuale, emulato per intenderci e scrive sullo stesso tag. L’emulazione viene messa a disposizione dalle librerie opzionali, Contactless Communication API scaricabili dal sito della nokia, che sarà dunque necessario rendere disponibili all’interno del progetto in eclipse. Lanciando l’applicazione avremo:

midlet-on-nfc

Ciò che si vede è l’interfaccia dell’emulatore con la midlet caricata e pronta per essere eseguita. L’emulatore sostanzialmente è un cellulare, nello specifico il nokia 6131 che possiede al suo interno un tag NFC con le relative librerie. Per avviare l’applicazione è sufficente cliccare il bottone (sul cellulare) in corrispondenza della voce Select.

midlet3-on-nfcL’applicazione come detto mostra il menù con 3 voce selezionabili, in particolare se selezioniamo l’opzione Read saremo in grado di leggere da un tag NFC un certo contenuto. Nella nostra simulazione, i tag NFC sono virtuali e vengono mostrati sulla destra nell’interfaccia dell’emulatore. Alcuni di questi sono attivi, connessi altri disconnessi. Per effettuare una simulazione di lettura trasciniamo il tag NFC attivo all’interno del cellulare come mostrato in figura. A quel punto il contenuto del tag viene mostrato all’interno del telefono.

Ma diamo un occhiata al codice che realizza la funzionalità. L’idea che sta dietro alla logica è molto semplice. Si registra la classe del Reader per un determinato evento, ovvero per l’evento Tag Detection. Rilevato il tag viene richiamato un metodo della classe che stabilisce una connessione con il tag e legge il messaggio inviato dal tag. Il contenuto del messagio viene visualizzato sul display del cellulare. Di seguito incollo il codice della classe Reader.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class NDEFReader extends NDEFHandler {
    Form previousScreen = null;
    public NDEFReader(Form form) {
        super();
        previousScreen = form;
    }
 
    public void targetDetectionMade(TargetProperties[] tProp) {
	previousScreen.append("Target detected.\n");
	if(tProp == null || tProp.length == 0) {
	    previousScreen.append("No TargetProperties found!\n");
	}
	NDEFTagConnection ndefConnection = null;
	try {			
	    previousScreen.append("Target mapping:"+tProp[0].getMapping()+"\n");				
	    ndefConnection =NDEFUtil.getNDEFTAGConnection(tProp,previousScreen);
	    if(ndefConnection == null) {
		previousScreen.append("Could not establish connection to card.\n");
		return;
	    }
	    NDEFUtil.readNDEFMessage(ndefConnection,previousScreen);
	    ndefConnection.close();
	} catch (Exception e) {
	    if(ndefConnection != null) {
	        try {
		    ndefConnection.close();
	        } catch (IOException e1) {
		    previousScreen.append("Exception in closing connection:"+e1.toString());
	        }
	    }
	    previousScreen.append("Exception:\n"+e.toString()+"\n");
	    e.printStackTrace();
        }
    }
 
    public String getFormattedName() {
        return null;
    }
 
    public void setFormattedName(String fName) {}
 
}

Il metodo targetDetectionMade realizza tutto quello che è stato detto nel paragrafo precedente. Per quanto riguarda il resto del codice rimando ai prossimi articoli. Stay tuned! yo

Crittare l’url di un immagine in jsp con Spring

DataObfuscationIn questo articolo voglio far vedere come nascondere l’href di un immagine in una pagine JSP, pur visualizzando l’immagine come elemento HTML in modo standard.
Supponiamo di dover sviluppare un’applicazione web in cui ciascun utente mantiene una libreria multimediale, costituita per semplicità da soli elementi immagine. Ogni immagine viene memorizzata all’interno di un database assieme alla relative informazioni dell’utente a cui appartiene.
Affinché l’immagine non sia accessibile semplicemente attraverso l’indirizzo indicato nell’HREF, è necessario offuscare il suo contenuto attraverso una codifica il cui funzionamento è noto al sistema. Lo stesso sistema sarà in grado così di decodificare l’HREF in modo da poter restituire la risorsa e quindi visulalizzarla all’interno della pagina.
Vediamo il seguente esempio:

1
2
3
4
5
   <!-- Immagine in chiaro -->
   <img src="http://host/images/img.jpg" title="Immgine in chiaro" alt="" />
 
   <!-- Immagine offuscata -->
   <img src="http://host/image.htm?a=QVMyJCU0c2Rm%3D&b=QVMyJCU0c2RmMzI0M3NkdzI%3D" title="Immgine in chiaro" alt="" />

Nell’esempio di sopra viene mostrata un’immagine in cui l’href è crittata secondo un algoritmo che ora vedremo. E’ chiaro che nel secondo caso, affinché l’immagine possa essere visualizzata è necessaria la presenza di un elemento capace di interpretarne il contenuto, ottenere e restituire la risorsa.
Nell’ambito di Spring tutto questo può essere tradotto nel modo seguente: è necessario un Controller che venga richiamato ogni volta in cui nella pagina è presente un’immagine.
Il Controller dovrà prelevare il contenuto dell’HREF decodificarlo e restituire l’immagine, se corretto. Procediamo quindi per step.
Primo Step configuriamo il Controller (Servlet) all’interno di Spring…quindi editiamo il file di configurazione di spring ed aggiungiamo le seguenti righe di codice:

1
2
3
4
5
6
7
8
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" id="urlMapping"> 
        <property name="mappings">
	<value>/image.htm=mediaResolver</value>
        <property value="true" name="alwaysUseFullPath"></property>
    </bean> 
    <bean class="it.devme.obfuscator.media.MediaResolver" id="mediaResolver">
        <property name="dbManager"><ref bean="dbManager"></ref></property>     
    </bean>

L’invocazione della risorsa virtuale index.htm provoca l’invocazione del Controller MediaResolver. Vediamo la sua struttura di seguito:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MediaResolver extends BaseCommandController {
 
    private DBManager dbManager;
    public void setDbManager (DBManager dbManager) {
	this.dbManager = dbManager;
    }
 
    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	Object mediaid = req.getParameter("a");
	Object uid = req.getParameter("b");
 
	if (mediaid==null || uid==null) 
	    return new ModelAndView(new MediaView("image/jpeg", "no-image.jpg", rs.getString("basePath"), MediaView.USE_DEFAULT_IMAGE));
 
	Encrypter dec = Encrypter.getInstance();
	int idaccount = Integer.parseInt(URLDecoder.decode(dec.decrypt(uid.toString()), "UTF-8"));
	int idelement = Integer.parseInt(URLDecoder.decode(dec.decrypt(mediaid.toString()), "UTF-8"));
 
	MediaBean media = null;
	File f = null;
	String mediaPath = null;
 
	/* Check if media item exists */
	media = dbManager.getImage(idelement, idaccount);
	if (media==null) return new ModelAndView();
	mediaPath = media.getPath();
	f = new File(UPLOAD_PATH + File.separator + mediaPath);
 
	MimetypesFileTypeMap mime = new MimetypesFileTypeMap();
 
	resp.setHeader("Cache-Control", "private,no-cache,no-store");
	resp.setContentType(mime.getContentType(f));
	return new ModelAndView(new MediaView(mime.getContentType(f), mediaPath, rs.getString("basePath"), !MediaView.USE_DEFAULT_IMAGE));
    }
 
}

La classe di sopra estende BaseCommandController e quando invocata viene richiamato l’unico metodo di cui è stato fatto l’override che si occupa di decodificare e restituire la risorsa. Vediamo come.
Sostanzialmente recupera i parametri dalla GET (nel nostro caso sono a e b). Li decodifica utilizzando un algoritmo di crittografia a noi noto (si può usare qualunque algoritmo a nostro piacimento basato su una chiave provata) e quindi ottiene per il parametro a, l’id dell’utente a cui appartiene la risorsa e per il parametro b, l’id della risorsa a cui si vuole accedere. Questi dati vengono passati in input ad un metodo che effettua una query su db (getImage(idelement, idaccount)) e verifica se effettivamente la risorsa richiesta appartiene all’utente corrente.
In caso contrario viene restituita una View vuota, altrimenti si determina il mime-type della risorsa e si restituisce una view creata a partire dalla classe MediaView.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MediaView extends AbstractView {
 
    private String media;
    private String basePath;
    private boolean noImage;
 
    public MediaView(String mime, String media, String basePath, boolean noImage) {
	this.media = media; 
	setContentType(mime);
	this.basePath = basePath;
    }
 
    @Override
    protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
	String rpath = 	null;
 
	rpath = this.basePath + request.getContextPath().substring(1) +
		MediaResolver.UPLOAD_PATH + File.separator + this.media;
 
 
	File f = new File(rpath);
	byte[] bytes = FileUtils.readFileToByteArray(f);
 
 
        // Write content type and also length (determined via byte array).
        response.setContentType(getContentType());
        response.setContentLength(bytes.length);
 
        // Flush byte array to servlet output stream.
        ServletOutputStream out = response.getOutputStream();
        out.write(bytes);
        out.flush();
    }
 
}

La classe MediaView non fa altro che leggere fisicamente i byte dell’immagine e restituirla nella response utilizzando un OutputStream. Il risultato è che l’immagine scritta nella response verrà visualizzata in pagina come un elemento HTML standard, mantenendo perà l’HREF dell’immagine crittato.
Alla prossima.

 

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