Etichette

Visualizzazione post con etichetta web programming. Mostra tutti i post
Visualizzazione post con etichetta web programming. Mostra tutti i post

lunedì 7 settembre 2009

Google Visualization API

Google mette a disposizione degli sviluppatori di applicazioni web una serie di API AJAX liberamente utilizzabili all'interno delle pagine HTML. Tali API permettono di arricchire in modo semplice le funzionalita di una pagina, per esempio, aggiungere mappe (Google Maps API), inserire la funzione di ricerca di google (Google AJAX Search API) oppure un meccanismo di traduzione all'interno delle proprie pagine web tramite Google AJAX Language API. E' disponibile una lista completa di tutte le AJAX API di google.

Le Google Visualization API, appartenenti anch'esse alle Google AJAX API, permettono di creare e visualizzare in modo molto semplice grafici di reportistica relativi a dati presenti in una qualsiasi sorgente di dati accessibile tramite il web e compatibile con le Visualization API. I dati da visualizzare possono essere strutturati in grafici, tabelle, mappe, grafi, etc...


Area ChartPie ChartIntensity mapOrg chart


Tali oggetti possono eventualmente catturare eventi, per esempio il click del mouse, e contenere dei link, permettendo di creare pagine ricche e interattive.
Per utilizzare le Visualization API è necessario seguire alcuni semplici passi:

1) Importare, nella sezione <head> della nostra pagina web, tramite il tag <script> il file JavaScript http://www.google.com/jsapi che definisce il 'core' delle Google AJAX API:      

 
<html>
<head>
<
script type="text/javascript" src="http://www.google.com/jsapi"></script>
...
</head>
<body>
...
</body>
</html>


2) Caricare, sempre nella sezione <head> della nostra pagina web, tramite il tag <script> le Google Visualization API e definire il tipo di visualizzazione che si vuole usare (es.: grafici a torta, grafici a barre, mappe, ...)

      
<html>
<head>

<script type="text/javascript">
//Carica le Visualization API e la visualizzazione a grafico di torta di Google
google.load('visualization', '1', {'packages':['piechart']});
</script>
<!--Carica la visualizzazione messa a disposizione da altri sviluppatori-->
<script type="text/javascript" src="http://www.example.com/fabulous_extension.js"></script>
...
</head>
<body>
...
</body>
</html>

3) Registrare un gestore di inizializzazione e visualizzazione di dati tramite una funzione che si occupa di (usando la funzione onLoad()):
    • preparare i dati da visualizzare: ad ogni oggetto Visualization è associato un oggetto (di tipo DataTable ) che contiene 'fisicamente' i dati da visualizare. Un DataTable è una tabella bidimensionale, con righe, colonne e celle. Tutte le celle di una stessa colonna devono contenere dati omogenei (tipicamente stringhe o numeri)


        var data = new google.visualization.DataTable();
       
// Declare columns and rows.
        data
.addColumn('string', 'Task');  // Column 0 is type string and has label "Task".
        data
.addColumn('number', 'Hours per Day'); // Column 1 is type number and has label "Hours per Day".
       
       
// Add data.
        data
.addRows([
         
['Work', 11],
         
['Eat', 2],
         
['Commute', 2],
         
['Watch TV', 2],
         
['Sleep', 7]
         
]);



    • creare un istanza dell'oggetto Visualization (nel seguente listato 'chart_div' è l'ID del <div> all'interno della pagina HTML in cui verra posizionato l'oggetto visualization, <div id="chart_div"> </div>)


var chart = new google.visualization.PieChart(document.getElementById('chart_div'));


    • registrare e ricevere eventi: tali eventi possono essere generati dall'utente, per esempio click o passaggio del mouse, oppure automatici, generati per esempio da un timer


    • visualizzare i dati (è possbile definire alcune proprieta dell'immagine visualizzata, per esempio il titolo e le dimensioni)


chart.draw(data, {width: 400, height: 240, is3D: true, title: 'My Daily Activities'}); 


4) visualizzare eventuali messaggi di errori in modo 'user-friendly' (ulteriori dettagli sulla visualizzazione di messaggi di errore).

venerdì 26 giugno 2009

Google Kaptcha

Nell'ambito dell'informatica con il termine captcha ("Completely Automated Public Turing test to tell Computers and Humans Apart") si intende un test volto a determinare se l'utente di un sistema informatico è un umano o un computer (comunemente detto 'bot'). Un test captcha tipicamente utilizzato è quello in cui si richiede ad un utente di scrivere quali siano le lettere o numeri presenti in una sequenza di lettere o numeri che appaiono distorti o offuscati sullo schermo (operaizone difficile, anche se non impossibile, per un bot).



Nello sviluppo di un applicazione web può essere utile prevedere un test captcha per esempio quando si vuole evitare che un sistema automatico crei degli account fittizzi per un sistema informatico riempendo delle form attraverso un bot.
Google mette a disposizione degli sviluppatori WEB java (JSP) delle librerie pronte all'uso che implementano un meccanismo di captcha. L'uso basico di tali librerie è molto semplice:
  1. occorre innanzitutto aggiungere delle librerie all'applicazione web, nella cartella WEB-INF/lib del file .war, 
  2. inserire all'interno della form un tag <img src="..."> il cui valore src matcha con l'url-pattern relativo alla servlet com.google.code.kaptcha.servlet.KaptchaServlet definito nel web.xml
  3. creare un riferimento alla servlet kaptcha nel descrittore web.xml,
  4. controllare, all'interno della servlet che gestisce i valori inviati con la form, che il valore captcha generato e messo all'interno della sessione web corrisponda con il valore inviato attraverso la form.

E' possbile aumentare la complessita dell'immagine generata settando opportunamente alcuni parametri (http://code.google.com/p/kaptcha/wiki/ConfigParameters) nel file web.xml:


URL correlati:
http://code.google.com/p/kaptcha/wiki/HowToUse

sabato 28 marzo 2009

Virtual Hosting

Il Virtual Hosting (o Shared IP Hosting) è la tecnica che permette di avere più siti web (domini) in esecuzione su una singolo web server fisico, con un unico indirizzo IP statico a disposizione. Nel virtual hosting basato sui nomi di dominio (name-based), esiste una relazione biunivoca tra host-name  (dominio) e virtual server, e le richieste in arrivo al server fisico vengono instradate opportunamente ad un particolare virtual server, in base all'host name definito nell'URL di richiesta. L' URL di richiesta è l'URL usato da uno User-Agent per richiedere ad un server una risorsa; in genere un web server può risopndere a richieste con URL di richiesta differenti (e tipicamente si tiene traccia di tali URL nel file di log delle richieste). Le seguenti due richieste hanno URL request differente, anche se la risposta sarà probabilmente la stessa:



Consideriamo la seguente tabella di mapping delle richieste in arrivo all'IP 127.0.0.1:


Protocollo
Dominio
Porta
Virtual Server
http
localhost
80
server
http
localhost181
server1


In un contesto JEE, disponendo per esempio di un server Glassfish, sarà sufficiente inserire nel file <glassfish-domain-path>/config/domain.xml quanto segue:

...
<http-listener id="http-listener-80" port"80">
<http-listener id="http-listener-81" port"81">
...
<virtual-server id="server" hosts="localhost" http-listeners="http-listener-80">
<virtual-server id="server1" hosts="localhost1" http-listeners="http-listener-81">
...

Tramite la console di amministrazione di Glassfish è facimente possibile creare nuovi http-listener





e virtual server:




Data la configurazione della tabella precedente, per una richiesta "http://localhost1" il server restituisce HTTP-CODE=404(risorsa non trovata), perchè tutte le richieste http in arrivo sulla porta 80(quella di default per le richieste http) vengono intercettate da http-listener-80 e non esiste un binding tra questo http-listener e il virtual server server1, che serve tutte e solo le richieste le cui URL request sono del tipo "http://localhost1:81/...".

Su un computer locale è possibile sperimentare tale situazione.
In ambiente Windows il file <WINDOWS_PATH>\system32\drivers\etc\hosts, che ha funzioni molto simili a quelle del DNS, opportunamente configurato permette di instradare tutte le richieste di tipo "<PROTOCOLLO>://localhost" e "<PROTOCOLLO>://localhost1" sull'host il cui IP è 127.0.0.1, cioè il computer locale:







in genere la riga "127.0.0.1    localhost" viene inserita di default in fase di installazione del S.O., quindi per il nostro esempio è sufficiente inserire la riga evidenziata in giallo.

In fase di deploy di un applicazione web (o enterprise) tramite la console di amministrazione è possibile specificare su quale virtual server debba essere deployata un'applicazione:




In altrenativa è possibile usare il comando asadmin deploy con l opzione --virtualservers, come riportato nella documentazione ufficiale. Per chi usa ambienti di sviluppo integrato è possibile effettuare il deploy direttamente su un particolare virtual server. Per esempio, usando Netbeans IDE e sfruttando le potenzialità di ANT, è possibile modificare il file <project-home>/nbproject/ant-deploy.xml inserendo un attributo nella tag <sun-appserv-deploy>:




Settando in maniera opportuna le proprietà di un virtual server è possibile, tra l'altro, impedire l'accesso a tale virtual server (e quindi a tutte le applicazioni in esecuzione su di esso) alle richieste provenienti da particolari indirizzi IP,  attraverso le proprietà denyRemoteAddress e allowRemoteAddress.

Ulteriori dettagli sull'utilizzo dei virtual server in ambiente JEE:
http://docs.sun.com/app/docs/doc/820-4507/abhfg?a=view
http://blogs.sun.com/jluehe/entry/virtual_hosting_features_in_glassfish




lunedì 23 marzo 2009

Inserire immagine favicon

In questo articolo ci occupiamo di come definire una favicon per un'applicazione web scritta in java. La favicon è la piccola immagine che viene visualizzata sul browser nella barra degli indirizzi a sinistra di un URL e che facilita l'individuazione del nostro sito quando viene aggiunto ai preferiti. Un classico esempio di favicon è l'icona che compare a sinisra dell' URL quando si accede alla home page di google.



Per rendere disponibile e visibile tale icona dobbiamo rispettare le seguenti specifiche:
  • il nome dell'immagine deve essere favicon.ico (non è sufficiente rinominare una gif, bmp, o altro, ma bisogna necessariamente disporre di un programma specifico per la generazione di immagini con estensione .ico, per esempio irfanview, liberamente scaricabile)
  • avere dimensioni 16x16 pixel






  • l'immagine deve essere disponibile all'URL http://<miosito.it>/favicon.ico. Per esempio se si usa Glassfish, l'application server realizzato da Sun Microsystems come implementazione di riferimento della specifica Java EE 5, bisognerà collocare l'icona in <glassfish_domain_path>\docroot, e non semplicemente nella root della nostra applicazione. L'icona sarà applicata a tutte le applicazioni che girano sul dominio glassfish_domain_path.

In alternativa, soprattutto se si vuole definire una favicon diversa per ognua delle applicazioni definite nello stesso dominio, nella sezione <head> delle pagine web in cui si voglia visualizzare la favicon deve essere inserita una tag link con attributi rel e href opportunamente definiti, al seguente modo:

<html>
    <head>
        <link rel="shortcut icon" href="favicon.ico">
    
    .....
    </head>
    <body>
        .....
    </body>
</html>


Per evitare l'operazione ripetitiva di dover definire in ogni pagina la tag link, è possibile utilizzare il meccanismo delle proprieta di gruppo di JSP(mediante <jsp-property-group> in web.xml). Per come abbiamo definito il contenuto di href nel nostro esempio è necessario che il file favicon.ico ora si trovi nella root della nostra applicazione, ma è comunque possibile collocare il file anche in una sottodirectory, per esempio /res, cambiando adeguatamente il valore di href:




Trattandosi di un'icona è opportuno, ma non necessario, istruire il container circa il mime-type del file favicon.ico. In un contesto di programmazione java lato server ciò si traduce nell'aggiunta di un nuovo <mime-mapping> nel descrittore web.xml:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="..." xmlns:xsi="..." xsi:schemaLocation="...">
    .....
    <mime-mapping>
        <extension>ico</extension>
        <mime-type>image/x-icon</mime-type>
    </mime-mapping>
</web-app>




venerdì 24 ottobre 2008

Upload di file

Per effettuare l'upload di un file sul server è necessario utilizzare le Commons FileUpload API (http://commons.apache.org/io) e le Commmons IO API (http://commons.apache.org/fileupload); le prime forniscono un meccanismo semplice, robusto e performante di upload di file ad un'applicazione web, le seconde un supporto allo sviluppo di funzionalità Input-Output e ci serviranno per memorizzare i file uplodati sul server.

La form che ci permetterà di selezionare un file lato client sarà del tipo:

<form action="UploadFile" method="post" enctype="multipart/form-data" accept="image" maxlength="100000">
<input type="file" name="fileUploaded"/>
<input type="submit" value="Send"/>
</form>

in cui l'attributo accept permette di filtrare il tipo di file uplodato e maxlength di specificarne la grandezza in byte massima. La servlet che processerà la richiesta sarà UploadFile la quale si aspetta, tramite richiesta POST, un parametro con nome fileUploaded. All'interno della servlet UploadFile inseriamo il seguente codice:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
ServletRequestContext src=null;
src = new ServletRequestContext(request);
if (FileUpload.isMultipartContent(src)){
DiskFileItemFactory dfif=null;
ServletFileUpload fu = null;
String path = "/upload/";
File file = new File(path);
if (!file.exists())
file.mkdirs();
dfif = new DiskFileItemFactory(size,file);
fu = new ServletFileUpload(dfif);
List itemList = null;
try{
itemList = fu.parseRequest(src);
}catch(Exception e){
response.sendError(500,e.getMessage());
return;
}
HashMap<String, FileItem> files
= getFileParameters(itemList);
FileItem fItem = files.get("fileUploaded");
String mime = fItem.getContentType();
int extIndex = mime.length()-3;
String ext = "."+mime.substring(extIndex);
String fileStr = fItem.getFieldName()+ext;
try{
fItem.write(new File(path+fileStr));
}catch(Exception e){
response.sendError(500, e.getMessage());
}
request.setAttribute("msg", "Upload OK");
}
RequestDispatcher rDisp;
ServletContext sc = this.getServletContext();
rDisp = sc.getRequestDispatcher("/info.jsp");
rDisp.forward(request, response);
}
/*
* estrae i FileItem della form e li
* inserisce in una Map in cui le chiavi
* sono i nomi dei parametri
*/
private HashMap<String, FileItem> getFileParameters(List itemList){
HashMap<String, FileItem> ret
= new HashMap<String, FileItem>();
Iterator iter = itemList.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()){
String fieldName = item.getFieldName();
ret.put(fieldName, item);
}
}
return ret;
}

Il metodo private HashMap<String, FileItem> getFileParameter(List itemList) in questo caso è poco utile, trattandosi dell'upload di un solo file, ma in genere permette di trattare i parametri di tipo non-FormField (quelli che contengono i file da uploadare) alla stregua dei classici parametri testuali, i quali possono essere inviati al server secondo un ordine non predefinito. I parametri non-FormField vengono inviati al server secondo l'ordine con cui vengono dichiarati nella form per cui una modifica della form potrebbe voler richiedere una modifica nella servlet.
Utilizzando HashMap<String, FileItem> il problema viene aggirato in quanto si fa riferimento ai vari FileItem di tipo non-FormField in base ai nomi e non alla posizione che occupano nella form.

ATTENZIONE: quando l' enctype definito nella form è multipart/form-data anche i tradizionali parametri testuali devono essere prelevati nella servlet usando la tecnica dell' HashMap ( con l'istruzione tradizionale request.getParameter("nomeparametro") il valore restituito è sempre null):

/*
 * estrae i parametri testuali della form e li
inserisce in una Map in cui le chiavi sono i nomi dei parametri
*/
private HashMap<String, String> getStringParameters(List
itemList){
    HashMap<String, String> ret = new HashMap<String, String>();
    Iterator iter = 
itemList.iterator();
    while (iter.hasNext()) {
        FileItem item = (FileItem) iter.next(); 
        if (item.isFormField()){
            String fieldName = item.getFieldName();
            String fieldValue = item.getString();
            ret.put(fieldName, fieldValue);
        }
     }
    return ret;
}

il valore di un parametro sarà prelevato attraverso la seguente istruzione:

....
HashMap<String, String> uploadedParameters = getStringParameters(itemList);
String parameterValue =  uploadedParameters.get("parameterName");
...

Alcuni IDE, per esempio Netbeans, permettono di aggiungere in maniera molto semplice un componente per l'uload di file in un applicazione JSF Visual Web (http://www.netbeans.org/kb/60/web/fileupload.html).

mercoledì 15 ottobre 2008

Contatore di Sessioni HTTP Attive

In un applicazione web scritta in Java è possibile contare il numero di sessioni http attive sul server tramite una classe che implementa javax.servlet.http.HttpSessionListener:

package web;
import javax.servlet.http.*;
public class SessionCounter implements HttpSessionListener {
private static int sessionCounter = 0;
public void sessionCreated(HttpSessionEvent evt) {
sessionCounter++;
}
public void sessionDestroyed(HttpSessionEvent evt) {
sessionCounter--;
}
public static int getSessionCounter() {
return sessionCounter;
}
}

In /WEB-INF/web.xml è necessario aggiungere un elemento per definire un application listener specificando il nome della classe appena creata:

<?xml version="1.0" ...>
<web-app>
<listener>
<listener-class> web.SessionCounter </listener-class>
</listener>
...
</web-app>

Infine è possibile conoscere ed eventualmente visualizzare su una pagina jsp il numero delle sessioni http attive nel seguente modo:

sul server ci sono <%=web.SessionCounter.getSessionCounter()%> sessioni attive

In genere tale conteggio può essere utile per capire quanti utenti sono presenti contemporaneamente su un sito web. Inoltre, aggiungendo una semplice struttura dati(p.e. un Vector aggiornato opportunamente quando vengono invocati i metodi sessionCreated e sessionDestroyed) alla classe SessionCounter, è possibile anche determinare quali utenti sono connessi al server in un dato istante.
Non è superfluo notare che il metodo public void sessionDestroyed(HttpSessionEvent evt) viene invocato sia nel caso in cui la sessione venga invalidata esplicitamente, per esempio attraverso un metodo logout(), sia che la sessione venga invalidata dal container, perchè scade il timeout di sessione attiva.

Sessioni HTTP Uniche

Vediamo come è possibile estendere il codice del post precedente per implementare facilmente un meccanismo per gestire il problema delle sessioni multiple per utente.
Definiamo una classe che ha la funzione di tenere traccia di tutte le sessioni http attive sul server mediante un HashMap.

package web;
import java.util.HashMap;
import javax.servlet.http.HttpSession;
public class SessionManager {
private HashMap sessions;
public boolean exist(String username) {
if (sessions.containsKey(username)) {
return true;
}
return false;
}
public boolean addSession(HttpSession session) {
if (sessions.containsKey( session.getAttribute("username"))) {
return false;
}
sessions.put((String) session.getAttribute("username"), session);
return true;
}
public HttpSession getSession(String username) {
return (HttpSession) sessions.get(username);
}
public boolean removeSession(String username) {
if (!sessions.containsKey(username)) {
return false;
}
sessions.remove(username);
return true;
}
private static SessionManager sessionManager;
public static SessionManager getSessionManager() {
if (sessionManager == null) {
sessionManager = new SessionManager();
}
return sessionManager;
}
public SessionManager() {
sessions = new HashMap();
}
}

Tale classe deve essere definita rispettando il pattern Singleton ed essere utilizzata all'interno di una servlet ogni volta che si vuole creare una nuova sessione, nel seguente modo

if(SessionManager.getInstance.exist(username)) {
     SessionManager manager = SessionManager.getInstance();
logout(manager.getSession(username) );
manager.removeSession(username);
}

in cui il metodo private void logout( HttpSession session) implementa le azioni necessarie ad invalidare la sessione.
Ovviamente, come descritto nel post precedente, è necessario aggiungere un elemento application listener in /WEB-INF/web.xml:

<?xml version="1.0" ...>
<web-app>
<listener>
<listener-class> web.SessionManager </listener-class>
</listener>
...
</web-app>

Meccanismo di lock su una coppia <username,password>:
Se si vuole usare il meccanismo illustrato per per fare in modo che per esempio una coppia <username,password> venga usata da un solo cliente alla volta basta riscrivere il codice utilizzato all'interno della servlet come segue:

if(SessionManager.getInstance.exist(username)) {
response.sendError(403);return;
}