Java EE - Un esempio su come usare EJB e componenti web

Java EE - Un esempio su come usare EJB e componenti web 
G.Morreale

Introduzione:

Lo scopo di questo articolo è quello di creare un applicazione enterprise in grado di sfruttare le seguenti tecnologie

  • Entity Bean
  • Session Bean
  • Servlet 
  • JSP

Java EE è una piattaforma molto vasta e riuscire a spiegare solo piccole parti di esse richiederebbe molto di più che un semplice articolo.
Nonostante ciò il tentativo è quello di dare un input al programmatore per stimolarne l'interesse e indurlo ad approfondire le singole tecnologie chiamate in ballo in questo esempio.

Al fine di velocizzare l'approccio a Java EE verrà utilizzato Netbeans e di conseguenza tutta la serie di wizard che l'IDE mette a disposizione.
Si cercherà inoltre di inserire nell'articolo dei link per approfondire circa i singoli passi eseguiti.

Cosa sarà in grado di fare l'esempio:

Il progettino che si creerà sarà in grado di estrarre i dati da un tabella di un dbms(mysql in questo caso) e stamparli tramite pagina web a video.

Cosa devo installare per realizzare l'esempio:


nota: Gli ultimi due non strettamente necessari, infatti è possibile effettuare operazioni analoghe con un altro dbms o rinunciare la tool grafico per le query.

I Passi per la realizzazione dell'esempio:

  1. Il Database
    1. Creare lo schema
    2. Creare una tabella
    3. Popolare la tabella
  2. Creazione Progetto Enterprise
  3. EJB
    1. Creare un datasource JDBC
    2. Creare un persistence unit
    3. Creare l'entity bean
    4. Creare un session facade per l'entity bean
  4. Modulo WEB
    1. Creare una servlet
    2. Creare una jsp

1. Il Database

Aprire il Mysql query browser loggandosi su localhost, si inserisca un nuovo DB chiamato EsempioDB con la seguente istruzione sql:

CREATE DATABASE `EsempioDB`;

Si crei la tabella:

CREATE TABLE `esempiodb`.`EsempioTable` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `testo` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`)
)
ENGINE = InnoDB;

E si popoli con le seguenti INSERT:

INSERT INTO EsempioTable VALUES(1,'TESTO 1');
INSERT INTO EsempioTable VALUES(2,'TESTO 2');
INSERT INTO EsempioTable VALUES(3,'TESTO 3');


2. Creazione Progetto "Vuoto"

Adesso si crei un nuovo progetto Enterprise selezionando "New Project" all'interno del file menu di netbeans.


Si scelga un nome, ad esempio, "Esempio" e si lascino inalterate tutte le opzioni richieste fino alla fine del wizard.
Ciò consente a netbeans di creare un progetto EJB, un progetto WEB e un progetto EAR in grado di inglobare EJB e WEB all'interno di unico archivio.

Come è possibile notare nella lista dei progetti saranno presenti i seguenti 3 progetti:

  • Esempio
  • Esempio-ejb
  • Esempio-war

nota:
Facendo un breve cenno al design pattern MVC gli ultimi due progetti conterranno rispettivamente il model(ejb) e controller/view(war).

3. EJB

Risorsa JDBC e PERSISTENCE UNIT

Adesso bisogna creare all'interno dell'application server una risorsa jdbc, ovvero una risorsa in grado di comunicare con il dbms e db creato.

nota:
Tale risorsa normalmente viene creata attraverso dei comandi propri dell'application server (es. in glassfish asadmin add-resources sun-resources.xml) o attraverso la console di amministrazione del server stesso, è quindi un operazione non di programmazione ma di amministrazione del container.
Nel caso di glassfish la risorsa jdbc viene creata attraverso un file xml nel quale si indicano una serie di parametri tra i quali username e password del database, numero di connesioni del pool etc.

Esempio di file xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Resource Definitions //EN" "http://www.sun.com/software/appserver/dtds/sun-resources_1_3.dtd">
<resources>
  <jdbc-resource enabled="true" jndi-name="esempioJNDI" object-type="user" pool-name="mysqlPool"/>
  <jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="mysqlPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
    <property name="serverName" value="localhost"/>
    <property name="portNumber" value="3306"/>
    <property name="databaseName" value="esempioDB"/>
    <property name="User" value="root"/>
    <property name="Password" value="123456"/>
    <property name="URL" value="jdbc:mysql://localhost:3306/esempioDB"/>
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
  </jdbc-connection-pool>
</resources>

Netbeans in automatico genera tale file xml e si occupa di comunicare a glassfish il deploy di tale risorsa.

Per far ciò si può passare direttamente a creare il persistence unit(sarebbe il passo successivo) e selezionare sulla combobox DataSource "New Data Source"
(Per ottenere tale finestra cliccare con il tasto destro sul progetto ejb e scegliere all'interno della categoria persistence: persistence unit.)

Cliccando su New Data Source si abbandona per un attimo la creazione del persistence unit e si passa alla creazione della risorsa per la comunicazione con il db.
Inizialmente verrà chiesto un nome JNDI e un URL jdbc.
Riguardo al primo è possibile scegliere un nome arbitrario,es. esempioJNDI

nota
Il nome jndi serve a identificare la risorsa all'interno del container, tale percorso però non verrà utilizzato direttamente nel codice in quando usando la dependency injection sarà il container stesso a trovare la risorsa (usando il percorso JNDI)

Riguardo la Database Connection, procedere scegliendo l'opzione "New Database Connection", apparirà un'altra finestra nella quale bisognerà indicare il tipo di driver jdbc da usare (mysql!) e i parametri di connessione.


Configurare il tutto correttamente in modo da ritornare alla finestra "New persistence Unit".

Sulla finestra "New persistence Unit" bisogna operare con le seguenti opzioni:

  • Persistence Unit Name: è il nome della configurazione del persistence unit

  • Persistence Provider: Indica quale librerie usare per gestire il mapping tra il database e la sua rappresentazione ad oggetti
(di default viene proposto toplink, ma ci sono altre valide alternative, personalmente preferisco hibernate ma per l'esempio si lasci toplink come opzione)

  • DataSource: è il nome del Datasource appena creato
  • Use Java Transaction API: Indica se far gestire alle JTA le transazioni o meno. (lasciare checked)

  • Table generation Strategy:Indica al persistence provider se creare o meno le tabelle nel caso in cui esistano gli entity e non le corrispettive tabelle. (in questo esempio le tabelle sono state create, ma si poteva direttamente creare gli entity che rappresentano le tabelle e lasciare che il persistence provider le generasse in automatico)

In definitiva scelto il nome del persistence unit (ad esempio - Esempio-ejbPU) è possibile proseguire cliccando su Finish lasciando tutte le opzioni inalterate.

Netbeans ha creato in automatico due file

  • sun-resources.xml - necessario alla creazione della risorsa jdbc sul server
  • persistence.xml - necessaria a indicare una serie di opzioni circa la gestione della persistenza (mapping O/R) etc.

Entity Bean

Cos'è un entity bean? E' un oggetto pojo in grado di rappresentare attraverso la notazione ad oggetti un tabella.
La corrispondenza tra entity bean e tabelle è gestista dal persistence provider (una serie di librerie).
Nel passo precedente è stato scelto TopLink come provider(le sue librerie sono installate di default).

nota:
Ne esistono di due tipi 

BMP - entity Bean Managed Persistence
CMP - entity Container Managed Persistence

I primi prevedono che il programmatore di occupi della logica di mapping tra gli entity e il database relazionale, i secondi si appoggiano al persistence provider. Nell'esempio si creerano degli entity CMP.

Tali bean possono essere creati in automatico attraverso l'ennesimo wizard di netbeans.

Tasto destro sul progetto ejb + Entity Classes From Databases..Scegliere il datasource "esempioJNDI" e scegliere le tabelle da sottoporre al wizard (1 sola in questo caso). 

Cliccare su next, indicare un package che contenga gli entity, ad esempio entities, cliccare su finish.

nota:
L'opzione "Generated named query annotation ..." serve a generare in automatico delle query all'interno dell'entity, tali query hanno il vantaggio di essere precompilate e quindi leggermente più performanti. In questo esempio comunque non ne viene fatto uso, per cui l'opzione è tralasciabile.

All'interno del package entities è possibile trovare l'entity bean, attraverso le annotations (@Table, @Column etc.) si indica al persistence provider come effettuare il mapping tra i dati del db e quelli nell'entity.

Session Bean

Cos'è un Session bean? E' un componente che gestisce la logica applicativa, nel classico esempio della banca si occuperà di effettuare le operazioni di bonifico, lista movimenti etc.

Ha un particolare ciclo di vita gestito dal container(attraverso pooling) e di solito vengono usati per la gestione del modello richiesta-risposta.

nota:
Esistono due tipi di session bean: Stateless e Stateful, la differenza consiste nel mantenimento delle informazioni tra client e server, solo i secondi infatti sono in grado di conservare tali dati.

Il session bean è composto dalla sua interfaccia e dalla relativa implementazione

nota:
Le interfaccie possono essere di due tipi, Locali e Remote, le prime si usano quando il modulo ejb e il modulo web risiedono all'interno della stessa applicazione enterprise (EAR), ovviamente sono più efficenti. Le seconde vengono usate qualora i moduli ejb e il modulo web(o altri moduli ejb) risiedono su applicazioni diverse o container diversi.

Si ricorre nuovamente al wizard di netbeans per creare in automatico un session bean in grado di implementare ed esporre attraverso interfaccia locale i più comuni metodi (inserimento, edit, cancellazione etc.) di interazione con l'entity appena creato.

Tasto destro sul progetto ejb - Session Bean For Entity Classes - scegliere l'entity - scegliere un package (es. session) -> Finish!!

All'interno del package session è stata creato il session bean e la relativa interfaccia.
L'interfaccia espone i metodi utilizzabili dall'esterno (es. modulo web:servlet)

Si dia uno sguardo all'implementazione del session bean

@Stateless
public class EsempiotableFacade implements EsempiotableFacadeLocal {

    @PersistenceContext
    private EntityManager em;

    public void create(Esempiotable esempiotable)
    {
        em.persist(esempiotable);
    }

    public void edit(Esempiotable esempiotable)
    {
        em.merge(esempiotable);
    }

    public void remove(Esempiotable esempiotable)
    {
        em.remove(em.merge(esempiotable));
    }

    public Esempiotable find(Object id)
    {
        return em.find(entities.Esempiotable.class, id);
    }

    public List<Esempiotable> findAll()
    {
        return em.createQuery("select object(o) from Esempiotable as o").getResultList();
    }

}

@Stateless indica banalmente il tipo di bean.

@PersistenceContext
private EntityManager em;

Serve a inizializzare l'EntityManager, ovvero quell'oggetto che si occupa del mapping fra entity e tabelle.
L'EntityManager è una delle classi chiave del persistence provider.
l'annotation @PersistenceContext permette al container di inizializzare la variabile em considerando le informazioni immesse all'interno del file persistence.xml (Si ricordi il persistence unit!!).
L'inizializzazione avviene attraverso il meccanismo della dependency injection (vedi mio articolo precedente).

i metodi "em.find, em.remove, em.merge, em. persist"
sono propri dell'entity manager e servono rispettivamente per le seguenti operazioni di base

  • em.find - > ricerca tramite id di un entity (corrisponde ad una SELECT ... WHERE id = :id)
  • em.remove -> eliminazione tramite id (corrisponde a DELETE .. WHERE id = :id
  • em.merge -> inserimento o update (INSERT o UPDATE) (serve anche a recuperare entity detached...)
  • em. persist -> inserimento dell'entity sul db (corrisponde alla INSERT)

Per realizzare delle operazioni specifiche attraverso delle query ad hoc si ricorre, come nell'ultimo metodo (findAll()), alla generazione di una query attraverso il metodo "createQuery"

Le query da sottoporre all'entitymanager devono essere scritte in EJB-QL, ovvero uno specifico linguaggio in grado di effettuare query sugli entity e non sulle tabelle. EJB-QL contribuisce a garantire la portabilità delle query attraverso dbms diversi (la query scritta infatti prescinde da mysql!).
Per approfondire su ejb-ql clicca qui.

Ovviamente bisogna imparare a scrivere i propri session bean ma l'esempio intende giusto a dare una panoramica..


Modulo WEB

Si è realizzata la logica di business, l'ejb è in grado di estrarre i dati dal db e comunicarli attraverso una struttura dati (List<Esempiotable>)

Adesso è possibile procedere creando una servlet in grado di richiamare il session bean.(Secondo il pattern MVC la servlet fungerà da controller).

Tasto destro sul modulo war -> New Servlet -> Servlet class name = test -> package = servlet -> Finish

Si svuoti il metodo processRequest   in modo che sia uguale alla porzione di codice seguente 

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException
{
    //clicca qui con il tasto dx.

Adesso si procede con l'inizializzazione (ancora una volta operata attraverso dependency injection) del componente ejb da richiamare.


Dove c'è il commento premere Tasto destro -> Insert code -> Call Enterprise Bean

(Ver Netbeans 6.0 "Dove c'è il commento cliccare con il tasto dx -> Enterprise Resources -> Call Enterprise Bean -> Scegliere Esempio-ejb -> EsempioTableFacade -> Finish")



In quest'ultimo caso il wizard è servito per inserire una sola riga di codice:

 @EJB
 private EsempiotableFacadeLocal esempiotableFacade;

Ovvero quella per l'inizializzazione del session bean.
Tale variabile non necessita ulteriori inizializzazioni (grazie all'annotation ci ha già pensato il container!), è quindi pronta all'uso.

All'interno di processRequest è quindi possibile digitare il seguente codice al fine di estrarre il contenuto della tabella.

List<Esempiotable> list =  esempiotableFacade.findAll();
//(non dimenticare di fare un fix delle import!)

Bene, già da subito si potrebbe nella servlet stessa stampare il contenuto della List attarverso un PrintWriter o similiari partendo dall'oggetto response.
Ma volendo rispettare il paradigma MVC e predisporre l'esempio per un uso più strutturato si decide di passare i dati a una view (una pagina JSP).

Al fine di passare i dati tra la servlet e la pagina jsp si usa la tecnica del forward attraverso un RequestDispatcher.

Il dispatcher può essere inizializzato nel seguente modo:

String arg = "/" + this.getServletName() + ".jsp";
RequestDispatcher dispatcher = this.getServletContext().getRequestDispatcher(arg);

il forwarding avviene attraverso l'istruzione

dispatcher.forward(request, response);

Tale tecnica non genera un redirect verso la pagina jsp, ma serve a indicare al container che il flusso viene passato dalla servlet alla jsp mantenendo inalterato lo stato dell'oggetto request e response.
In tal modo è quindi possibile comunicare i dati contenuti nella "list" alla jsp settandoli all'interno dell'oggetto request operando nel seguente modo:

request.setAttribute("lista", list);

quindi in definitiva il codice di processRequest sarà il seguente:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException  {
        
            List<Esempiotable> list =  esempiotableFacade.findAll();
  
            request.setAttribute("lista", list);
            
            String arg = "/" + this.getServletName() + ".jsp";
            RequestDispatcher dispatcher = this.getServletContext().getRequestDispatcher(arg);
            dispatcher.forward(request, response);
            
    } 

Adesso si crei una jsp con lo stesso nome della servlet (test.jsp) (Secondo MVC stiamo realizzando una view)

Il codice della jsp è il seguente:

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@page import="entities.Esempiotable"%>
<%@page import="java.util.List"%>
<%
List<Esempiotable> list = (List<Esempiotable>)request.getAttribute("lista");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
    <h1>Contenuto Tabella EsempioTable</h1>
    <% if (list != null) 
        { for (Esempiotable e: list)
              { out.println(e.getId() + " " + e.getTesto() + "<br/>"); }
        }           
    %>    
    </body>
</html>

Il codice è banale, si estrae dall'oggetto request l'attributo lista e successivamente all'interno del codice html si effettua un ciclo for attraverso la lista al fine di stampare il contenuto dei vari entity.

Cliccando su Run sull'Enterprise Application Esempio e digitando sul browser
http://localhost/Esempio-war/test

L'output ottenuto sarà simile alla seguente immagine:




Conclusione:

Questo articolo è solo un introduzione al mondo java EE, di cose da spiegare ed esplorare ce no sono veramente tante.. Questo è solo l'inizio!



Cenni sulla Dependency Injection

Dependency Injection
G.Morreale

Introduzione:

La Dependency Injection è un pattern di programmazione, nello specifico è una particolare forma del pattern Inversion Of Control.
Con la Dependency Injection una classe o un sistema non è responsabile circa l'inizializzazione delle proprie dipendenze.

Cercherò prima di fare un pò di chiarezza sui termini.

Cos'è una "Dependency"?.. Banalmente è un modo diverso di chiamare le variabili di un classe, i suoi campi, o se si preferisce la variabili di istanza.

public class Esempio
{
private Risorsa risorsa;

public void Esempio()
{}

public void foo()
{
..
risorsa.faiQualcosa();
..
}
}


risorsa è una Dependency.

Cos'è "Injection"?..Non è altro che l'inizializzazione della variabile o se si vuole della Dependency!

Per realizzare una Dependency Injection attraverso il costruttore possiamo modificare l'esempio nel seguente modo:

public class Esempio
{
private Risorsa risorsa;

public void Esempio(Risorsa r)
{risorsa = r;}

public void foo()
{
..
risorsa.faiQualcosa();
..
}
}


L'injection avviene quando all'esterno della classe che contiene la Dependency (la variabile di istanza da inizializzare) si passa la dependency stessa già inizializzata.

public class EsempioTest
{
public void Test()
{
Risorsa r = new Risorsa("bla bla");
Esempio esempio = new Esempio(r);
esempio .foo();
}
}


In questo caso la Dependecy Injection è avvenuta tramite costruttore, ma tale tecnica può essere realizzata con un metodo "set" o tramite l'interfaccia.

Esistono infatti 3 tipi di Depency Injection:

  • Constructor Injection
  • Setter Injection
  • Interface Injection

A cosa serve la Dependency Injection?

L'obiettivo di tale tecnica è quello di allentare l'associazione(coupling) tra un oggetto e ed un altro.
Per approfondire circa l'utilità del pattern è consigliabile la lettura di questo articolo http://docs.google.com/View?docid=dg4p5693_22h76wp

La riduzione della dipendenza tra una classe e l'altra, inoltre, facilita le fasi di unit testing rendendo tale pattern adatto per progetti basati sul Test Driven Development(http://www.javaportal.it/rw/43650/editorial.html )

Dependency Injection e Java EE

Nella versione J2EE 1.4 si utilizzava la tecnica del JNDI lookup, la classe che intendeva usare una risorsa/servizio doveva dichiarare esplicitamente tale dipendenza e ottenerla attraverso il JNDI lookup.

Context ic = new InitialContext();
HelloWorld helloWorld = (HelloWorld)ic.lookup("java:comp/env/ejb/HelloWorld");

Con le nuove specifiche è il container che si occupa di effettuare tale lookup e inizializzazione per conto della classe che intende usare tale dipendenza. La classe deve solo indicare che intende usare la dipendenza:

@EJB
private HelloWord hello;


altri esempi

@PersistenceContext
private EntityManager em;

@WebServiceRef
private SmsWebService service;

Le annotation (@EJB, @PersistenceContext etc.) supportano dei parametri che consentono di indicare al container il nome della risorsa, la tipologia e altre opzioni. Ad esempio nel caso del PersistenceContext, nel caso in cui esistono all'interno del modulo ejb due diversi persistence unit è necessario indicare il nome del persistence unit da utilizzare.

@PersistenceContext(unitName="p1")
private EntityManager em1;

@PersistenceContext(unitName="p2")
private EntityManager em2;

Visto che il responsabile di tale operazione di "Injection" è il container il pattern può essere usato solo per le classi managed, quelle unmanaged useranno,ad esempio, la tecnica del JNDI lookup.

Di seguito la lista delle managed class divise per tipologia di container(Web/EJB)

Web (Tipi di risorsa validi per l'injection: DataSource, JMS, Mail, EJB, Environment entries, EntityManager, UserTransaction)
  • Servlet,
  • listener classes,
  • web services end-point,
  • JAX-RPC handlers

EJB (Tipi di risorsa validi per l'injection:DataSource, JMS, Mail, Environment entries, EntityManager, EJB Context, UserTransaction, TimerService)
  • Bean,
  • interceptors,
  • web services end-point

Conclusione

Conoscere la Dependency Injection quindi serve a capire quali meccanismi stanno dietro l'inizializzazione invisibile di quei particolari campi preceduti dall'annotation(@EJB, @TimerService etc.)

Inoltre è possibile in fase di design dei propri progetti implementare tale pattern qualora si necessario disaccoppiare le componenti del progetto.

Java - Passaggio Valori

Java - Passaggio Valori
G.Morreale

Introduzione:

Questo è un argomento base, ma spesso c'è parecchia confusione circa il passaggio dei valori in Java.
Proprio di recente ho letto un articolo http://www.javaranch.com/campfire/StoryCups.jsp
che tratta l'argomento attraverso delle similitudini, è proprio basandomi su tale testo che vorrei fare un pò di chiarezza a riguardo.

Supponiamo che le variabili siano dei cassetti di un mobile (Il mobile potrebbe essere paragonato all'heap)

I cassetti essenzialmente contengono due tipi di "cose"

  1. oggettini vari (penne, lampadine, libri)
  2. telecomandi (tipo quello della tv o dello stereo per intenderci)

Gli oggettini sarebbero i dati primitivi (byte, short, int, float, double).
Tali oggetti sono contenuti in cassetti di dimensione variabile, le penne infatti sono contenute dai cassetti grandi 15 cm2, mentre i libri sono contenuti da cassetti un pò più capienti allo stesso modo in cui i byte necessitano variabili da 8 bit mentre gli int necessitano 32 bit di spazio.

Quando viene chiamato un metodo passando un data primitivo, viene aperto ("allocato") un nuovo cassetto vuoto e all'interno viene copiato il dato(NON travasato).

Tale metodo si chiama "passaggio per valore".

I telecomandi invece sono contenuti in cassetti di ugual dimensione.
I telecomandi servono a comandare, come scrivevo prima tra parentesi, oggetti vari come la tv, lo stereo il dvd recorder etc. etc.

Bene, la tv, lo stereo etc. sono gli oggetti java (es. new Date()) e i telecomandi servono a "utilizzare" tali oggetti.

In questo caso quando viene chiamato un metodo e viene passato l'oggetto viene aperto("allocato") un nuovo cassetto e all'interno viene messa una copia del telecomando in grado di "comandare", "utilizzare" lo stesso oggetto del telecomando originale.

esempio:

public void foo(Date val)
{
/*val avrà una copia del riferimento(telecomando) in grado di gestire l'oggetto new Date() come avviene per now.*/
}

Date now = new Date();
foo(now);

Quindi si hanno due telecomandi differenti che gestiscono la stessa tv.
Modificando - val - non si andrà ad intaccare il riferimento di now e viceversa, però utlizzando attraverso val i metodi dell'oggetto Date si potrà modificare l'oggetto e anche now sarà al corrente di tali modifiche.


import java.util.Date;

public class Main
{

    public static void main(String[] args)
    {
        Date now = new Date();
        System.out.println("Now - prima di foo - " + now.toString());
        Prova prova = new Prova();
        prova.foo(now);
        System.out.println("Now - dopo foo - " + now.toString());
    }
}

class Prova
{
    public void foo(Date val)
    {
        val.setTime(0);
               val = null;
    }
}

Quindi l'output del precedente esempio sarà

Now - prima di foo - Thu Oct 02 15:27:57 CEST 2008
Now - dopo foo -     Thu Jan 01 01:00:00 CET 1970

Ciò dimostra che attraverso copie diverse dei telecomandi(riferimenti) si agisce sullo stesso oggetto.
All'interno di foo l'assegnamento 

val = null

dimostra come i riferimenti siano stati passati per valore, quindi sono copie diverse.
now non può modificare il valore di val e viceversa ma entrambi possono modificare il valore dello stesso oggetto a cui puntano.

Oggetti Immutablii

Nel caso in cui gli oggetti trattati dai riferimenti(telecomandi) siano immutabili

Le classi Immutable sono read-only cioè non ci sono metodi SetField. I dati della classe sono definiti per sempre nel costruttore (e ovviamente sono privati). Esempio di classi Immutable sono String e Integer.
Si evitano così problemi di accesso concorrente ai dati della classe, poiché non ci sono metodi che modificano lo stato dell'oggetto dopo la sua creazione
.

L'output del seguente esempio necessita di alcune considerazioni

public class Main
{
    public static void main(String[] args)
    {
        String now = new String("ABC");
        System.out.println("Prima di Foo " + now.toString());
        Prova prova = new Prova();
        prova.foo(now);
        System.out.println("Dopo Foo " + now.toString());
    }
}

 class Prova
{
    public void foo(String val)
    {        
        val = val + "D";
        val = null;
    }
}

Nel momento in cui il valore now viene preso in considerazione dal metodo foo, val conterrà una copia del riferimento che punterà alla stringa "ABC", ma quando si eseguirà

  val = val + "D";

essendo String un oggetto immutabile verrà creato un nuovo oggetto contenente "ABCD", val quindi punterà a tale oggetto e non più a quello vecchio.
Però essendo val una copia del riferimento di now, now non sarà modificato e quindi continuerà a puntare verso l'oggetto "ABC".

Quindi l'output del precedente esempio sarà

Prima di Foo ABC
Dopo Foo ABC



Glassfish Cluster: LoadBalancer with Apache

Glassfish Cluster: LoadBalancer with Apache
G.Morreale

Introduzione:

Il loadbalancer, ha il compito di ripartire il traffico tra i diversi nodi del cluster.

La ripartizione del carico tra i vari nodi del cluster può essere realizzata in diversi modi:
LVS, mod_jk, plugin di glassfish, Rewrite Rule su Apache, usando dell'hardware dedicato etc. etc.
L'obiettivo è comunque quello di interrogare i diversi nodi secondo un determinato algoritmo in modo da caricare i vari nodi secondo le esigenze del sistema.

Nei passi successivi si fà riferimento alla configurazione di un LoadBalancer che sfrutta il plugin di glassfish che considera come ripartitore di traffico il webserver apache.

Usare la soluzione "plug-in" comparta i seguenti vantaggi:

- Integrazione con l'application server
- Possibilità di configurazione di loadbalancing direttamente da admin console:
- Sistema di integrato di Health Checking, il modulo infatti determina se un istanza non è in grado di rispondere al fine di eliminarla dal processo di ripartizione di carico.


- Configurazione dell'algoritmo di ripartizione del carico, con possibilità di caricare un modulo user-defined.

- Configurazione automatica del modulo di balancing, il plugin consente di esportare automaticamente o manualmente il file di configurazione per il modulo in modo da metterlo a corrente, anche in real-time, sulla struttura del cluster (ad es. aggiunta o eliminazione dei nodi).


Premessa:

La comunicazione tra il webserver che agisce da loadbalancer e il DAS avviene tramite SSL.
E' necessario quindi abilitare sul server apache il supporto per SSL.

Il plugin per glassfish considerato è compatibile con apache 2.0.x(versione 32 bit),
quindi non usare la più recente 2.2 o successive.

I passi da eseguire si dividono nelle seguenti macro-operazioni:

  • Installare e Configurare Apache con supporto SSL
  • Installare il plugin e configurare Apache affinchè comunichi con il plugin
  • Creare e abilitare il plugin all'interno del DAS


Installare e Configurare Apache con supporto SSL

I seguenti passi si riferiscono alla piattaforma Windows:
Per Linux o Solaris è possibile seguire una delle molteplici guide sul web o in alternativa consultare la guida fornita dalla sun

Scaricare una versione di Apache con openssl:

  • Abilitare il modulo su httpd.conf togliendo il commento '#'

LoadModule ssl_module modules/mod_ssl.so


  • Assicurarsi dell'esistenza in httpd.conf delle seguenti righe

<IfModule mod_ssl.c>
   Include conf/ssl.conf
</IfModule>


  • Generare il certificato e la chiave per apache

%ApacheDIR%bin openssl.exe req -new -x509 -keyout newreq.pem -out newreq.pem -days 365 -config "%ApacheDIR%confopenssl
.cnf"
(sostituire opportunamente la path per il file openssl.cnf usato)
nota: la generazione del certificato crea dei problemi con la variabile di ambiente che indica la locazione della configurazione openssl, meglio usare lo switch -config come nell'esempio.


ATTENZIONE: il common name richiesto deve corrispondere all'hostname usato su apache. Tale valore corrisponderà poi durante la configurazione del plug in su glassfish al device host.


  • Aprire con un editor di testo il file newreq.pem

  • copiare la porzione che và da 

-----BEGIN CERTIFICATE----- 
a
-----END CERTIFICATE-----

nel file %ApacheDIR%/conf/ssl.crt/server.crt

copiare invece la porzione che và da 
-----BEGIN RSA PRIVATE KEY----- 
a
-----END RSA PRIVATE KEY-----

nel file %ApacheDIR%/conf/ssl.key/server.key


Nota: Se è stata immessa una passphrase durante la generazione della chiave, il file server.key avrà una versione crittografata della chiave. Apache dovrebbe quindi mostrare durante l'avvio una finestra di dialogo per la digitazione della passphrase.
Tale finestra di dialogo NON è supportata in windows, quindi bisogna eliminare la passphrase dalla chiave con il seguente comando:

%ApacheDIR%/bin/openssl rsa -in server.key -out serverNoPhrase.key

Il serverNoPhrase.key ottenuto è senza passaphrase. Assicurarsi che nel file ssl.conf si punti a tale file piuttosto che a quello crittografato oppure ricopiare serverNoPhrase.key in server.key e cancellare serverNoPhrase.key.
.

  • Avviare Apache in SSL mode. In windows il comando è il seguente:
apache -D SSL

  • Testare il funzionamento di apache ssl con il browser non dimenticando di usare https.

ATTENZIONE: Ci potrebbero essere dei conflitti nell'uso delle porte tra glassfish e apache.
Leggendo i log (error.log in apache) o (server.log in glassfish) identificare il conflitto e operare di conseguenza.



Installare il plugin e configurare Apache affinchè comunichi con il plugin

  • Scaricare il plugin dai seguenti link: 

SOLARISX86    http://download.java.net/javaee5/external/SunOS_X86/aslb/jars/aslb-9.1-MS4-b1.jar
SOLARIS       http://download.java.net/javaee5/external/SunOS/aslb/jars/aslb-9.1-MS4-b1.jar
WINDOWS     http://download.java.net/javaee5/external/WINNT/aslb/jars/aslb-9.1-MS4-b1.jar
LINUX            http://download.java.net/javaee5/external/Linux/aslb/jars/aslb-9.1-MS4-b1.jar

nota: navigare su http://download.java.net/javaee5/external/ per ricercare eventuali versioni più recenti o altre piattaforme supportate

In questa configurazione è stato utilizzato "aslb-9.1-MS4-b7.jar"

  • Scompattare il file .jar usando il comando jar -xvf nomefile.jar o utilizzando un archiver come WinRar.
  • I file zip ottenuti (SUNWaslb.zip e SUNWaspx.zip) devono essere scompattati all'interno della cartella lib/lbplugin dell'application server
quindi creare la cartella "lbplugin" su %GLASSFISH_HOME/lib/ e scompattare il contenuto all'interno dei due file .zip

nota: in linux assegnare i permessi con il comando: chmod -R 755 <GLASSFISH_HOME>/lib/lbplugin/lib

  • Copiare il file mod_balancer.dll presente in <GLASSFISH_HOME>/lib/lbplugin/lib/webserver-plugin/windows/apache2/
all'interno della directory modules di Apache.

  • Creare e copiare all'interno di %ApacheDir%/modules/resource i file .res presenti in <GLASSFISH_HOME>/lib/lbplugin/lib/webserver-plugin/windows/apache2/

  • Creare e copiare all'interno di %ApacheDir%/modules/errorpages i file presenti in <GLASSFISH_HOME>/lib/lbplugin/lib/webserver-plugin/windows/apache2/errorpages

  • Creare e copiare all'interno di %ApacheDir%/sec_db_files i file .db presenti in <GLASSFISH_HOME>/lib/lbplugin/lib/webserver-plugin/windows/apache2/

  • Copiare all'interno di %ApacheDir%/conf il file loadbalancer.xml.example presente in <GLASSFISH_HOME>/lib/lbplugin/lib/install/templates/loadbalancer.xml.example 
e rinominarlo loadbalancer.xml

  • Riavviare Apache in modalità SSL



Creare e abilitare il plugin all'interno del DAS

E' consigliabile in questa fase del setup aprire delle console in grado di leggere in tempo reale i contenuti dei file di errori dei log (server.log per glassfish e error.log per apache, inoltre nel caso del cluster leggere non solo il server.log del dominio ma anche quello di nodi e istanze varie)

Effettuare il login sull'admin console del DAS, posizionarsi sull'icona HTTP Load Balancers e Cliccare su New per creare un nuovo riferimento al load balancer.


  • Scegliere un nome per il load balancer, ad esempio apacheLB
  • Indicare come Device Host, l'hostname di apache lo stesso presente nella configurazione ssl.conf, lo stesso digitato nel common name durante la creazione del file newreq.pem (certificato + chiave)
  • Indicare come Devce Admin Port, il numero di porta ssl di apache (di default è 443)
  • Selezionare il corretto target in modo che il loadbalancer punti sul cluster
  • Il checkbox Automatically Apply Changes può essere selezionato se si vuole notificare automaticamente al modulo di balancing di apache riguardo ai cambiamenti di struttura del cluster (es. aggiunta o eliminazione di nodi istanza)
  • Dopo il salvataggio testare la configurazione selezionando apacheLB e cliccando su Test Connection

Nota: Nella sezione Export del LoadBalancer esiste la possibilità di esportare il file di configurazione loadbalancer.xml necessario al modulo di balancing di apache o modificarlo direttamente cliccando su "Apply Changes Now".
Riguardo la generazione automatica del file xml sulla directory di apache su linux bisogna settare correttamente i vari permessi.

Accertarsi inoltre che le istanze all'interno del cluster abbiano abilitato il load balancing (Cliccare sul "Enable Load Balancing" come da immagine)

Il Plug In è configurato.

Installare un applicazione su cluster e verificare dal browser se risponde uno dei nodi richiamando

http://apache_hostname/path_applicazione_cluster

Nota: la configurazione che è stata realizzata usa SSL per la comunicazione tra DAS e apache, Il load balancing invece avviene usando il normale protocollo http.

Possibili Problemi

Provando a inoltrare richieste ripetute verso il loadbalancer si potrebbero verificare i seguenti errori (vedi error.log di apache)

[warn] lb.runtime: RNTM2024: Daemon http://MOBISERVER:38081 is unhealthy.
[warn] lb.runtime: RNTM2030: Daemon Monitor : http://MOBISERVER:38081 : could be because daemon is down
[warn] lb.runtime: RNTM2025: Daemon http://mobipc:38080 is healthy.
[warn] lb.runtime: RNTM2025: Daemon http://mobipc:38080 is healthy.
[warn] lb.runtime: RNTM2025: Daemon http://mobipc:38080 is healthy.
[warn] lb.healthchecker: HLCK3003: Listener: http://MOBISERVER:38081 is detected to be still unHealthy in cluster: cluster
[warn] lb.healthchecker: HLCK3003: Listener: http://MOBISERVER:38081 is detected to be still unHealthy in cluster: cluster
[warn] lb.healthchecker: HLCK3003: Listener: http://MOBISERVER:38081 is detected to be still unHealthy in cluster: cluster
[warn] lb.healthchecker: HLCK3003: Listener: http://mobipc:38080 is detected to be still unHealthy in cluster: cluster
[warn] lb.healthchecker: HLCK3003: Listener: http://mobipc:38080 is detected to be still unHealthy in cluster: cluster

Se le istanze del cluster sono nello stato running e rispondo se chiamate direttamente sui rispettivi ip:porta vuol dire che potrebbe esserci qualche problema nell'httpd.conf, è necessario infatti controllare che i virtual host e server name vari abbiano il corretto nome.

Inoltre il file error.log di Apache viene continuamente aggiornato dal modulo mod_balancer, quindi provvedere opportunamente alla rotazione automatica del file di log oppura a impostare un log-level diverso.

Link di riferimento:


Glassfish Cluster and EJB Timer

Glassfish Cluster and EJB Timer
G.Morreale

Introduzione:

Una delle caratteristiche delle specifiche ejb, è il servizio "Timer Service".
Esso consente di attivare timer per determinati periodi di tempo o allo scadere di determinate date.


Tale servizio si appoggia su un database embedded in glassfish.
Navigando nell'admin console tra i connection pool (vedi risorse JDBC) è possibile notare infatti il connection pool "__TimerPool" utilizzato dalla risorsa __TimerPool.

Tale risorsa è disponibile di default solo per il target "server", quindi il cluster non è nemmeno a conoscenza di un db in grado di supportare il timer service.

Inoltre il database embedded non risulta adeguato in quanto le istanze del cluster non possono accedere a tale db e conoscere quindi lo stato della gestione del timer service.

Dovendo distribuire su glassfish cluster un EJB che utilizza il timer service bisogna configurare un db esterno in grado di supportare le transazioni e garantire che solo un istanza gestisca il timeout senza replicare gli eventi più del necessario.

Passi per la Configurazione:

Per configurare il cluster affinchè esso supporti il servizio EJB Timer è necessario seguire i seguenti passi

- Creare un db (es. TIMER_DB)

- Creare all'interno una tabella usando gli script sql che si trovano all'interno di $GLASSFISH_HOME/lib/install/databases
   Lo script mysql non è presente lo potete copiare da qui:

CREATE TABLE EJB__TIMER__TBL (
    CREATIONTIMERAW      BIGINT        NOT NULL,
    `BLOB`               BLOB,
    TIMERID              VARCHAR(255)  NOT NULL,
    CONTAINERID          BIGINT        NOT NULL,
    OWNERID              VARCHAR(255)  NOT NULL,
    STATE                INTEGER       NOT NULL,
    PKHASHCODE           INTEGER       NOT NULL,
    INTERVALDURATION     BIGINT        NOT NULL,
    INITIALEXPIRATIONRAW BIGINT        NOT NULL,
    LASTEXPIRATIONRAW    BIGINT        NOT NULL,
    CONSTRAINT PK_EJB__TIMER__TBL PRIMARY KEY (TIMERID) 
) ;

nota: il nome della tabella deve essere maiuscolo

- Creare all'interno di "Resource->Connection Pools" un pool in grado di comunicare con il db creato.

- Creare una risorsa jdbc che punta al connection pool appena creato.
La risorsa creata deve avere come target il cluster, per garantire ciò è possibile creare la risorsa cliccando su 
"Cluster->nome cluster->Resources->New->JDBC Resources"

- Andare sulla configurazione del cluster (Quella di default si chiama cluster-config), 
selezionare EJB-container, 
cliccare su EJB Timer Service 
settare nel campo Timer Datasource il nome della risorsa jdbc creata nel passo precedente.

- Riavviare il cluster.

Driver XA  e Possibili problematiche

Per fare un buon setup bisogna creare, come peraltro ho suggerito precedentemente, una risorsa jdbc apposita per il timer.
Tale scelta però può creare dei problemi nel momento in cui l'applicazione che fà uso del timer service contemporaneamente accede ad una risorsa jdbc differente (ad esempio mediante hibernate si effettua l'accesso al connection pool del db dell'applicazione).

In tal caso uno stesso bean deve accedere a due risorse contemporaneamente e garantire le proprietà ACID.
Per far ciò è necessario disporre di un driver JDBC XA-capable

Tale driver ovviamente deve essere disponibile nel classpath, ad esempio copiandolo nella directory /lib del dominio (di default domain1).
(nota: quando aggiorni una libreria è necessario riavviare l'application server)

Nel caso di mysql, il connector J (attualmente alla versione 5.1.6) è XA compatibile.

Oltre ad avere un driver con le suddette caratteristiche è necessario impostare il connection pool affinchè tali caratteristche vengano usate.
Quindi nel connection pool creato si dovrà settare come Resource Type "java.sql.XADataSource", nel campo DataSourceClassName invece bisognerà settare il corretto valore in base al dbms utilizzato

Nel caso di mysql tale classe è 
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource


Purtroppo al momento il connector J crea dei problemi dovuti al bug:http://bugs.mysql.com/bug.php?id=35489

Di conseguenza durante il riavvio del timer (Ad esempio quando viene riavviata un instanza del cluster) si otterà la seguente eccezione:

INFO: Exception thrown from bean; nested exception is: java.lang.IllegalArgumentException: null source jav... 

Caused by: java.lang.IllegalArgumentException: null source
at java.util.EventObject.<init>(EventObject.java:38)
at javax.sql.StatementEvent.<init>(StatementEvent.java:39)
at
com.mysql.jdbc.jdbc2.optional.JDBC4PreparedStatementWrapper.close(JDBC4PreparedStatementWr
apper.java:70)
at com.caucho.sql.UserStatement.close(UserStatement.java:127)
at com.caucho.sql.UserPreparedStatement.close(UserPreparedStatement.java:450)
at org.hibernate.jdbc.AbstractBatcher.closePreparedStatement(AbstractBatcher.java:534)

causata dal bug in questione.

Al fine di risolvere la problematica, in attesa di una nuova release è possibile utilizzare una nightly build del connector j che prevede la correzione del bug.
(nota: quando si reinstalla una libreria jar in glassfish bisogna riavviare).

Io ho risolto con quella del 20 settembre.



Setup di Glassfish Cluster

Glassfish Cluster
G.Morreale

Introduzione:

Un cluster in genere è costituito da una macchina che funge da amministratore e una serie di nodi che svolgono il lavoro delle applicazioni installate su di essi.
L'obiettivo di un cluster di solito è quello di migliorare la scalabilità e l'alta affidabilità del sistema.

La macchina che agisce come amministratore nel glassfish clustering viene chiamata DAS (Domain Administrator Server). 

Ciascuno dei nodi invece è costituito da 2 elementi:

1) Node Agent: Gestisce il ciclo di vita dell'istanza al quale è associato.
2) Istanza: Istanza dell'application server..

Le applicazioni si installano sul DAS e vengono automaticamente propagate nei nodi.


Supporto Cluster

Il supporto cluster deve essere installato solo sulla macchina DAS.


Il glassfish può essere installato direttamente con il supporto cluster attivo oppure è possibile attivarlo anche in seguito a un'installazione standard.

  • Per attivare il supporto in fase di installazione usare il seguente comando: % libantbinant -f setup-cluster.xml al posto di % libantbinant -f setup.xml

  • Per attivare il supporto in seguito (vedi immagine sopra):
    • - Aprire l'admin console
    • - Selezionare tra i common task: Enable Cluster Support
    • - Cliccare su Ok


E' stata predisposta in questo modo la macchina che costituirà il DAS.

Setup Cluster con un nodo

Si supponga di voler creare un cluster minimale (non ha senso in situazioni reali):

Un unica macchina sarà DAS e unico nodo (in seguito aggiungiamo il secondo nodo).

Sulla macchina(DAS) nella quale è stato attivato il supporto cluster si crei il primo nodo.

nota: I nodi si possono creare solo da linea di comando. Dal pannello si può aggiungere un nodo ma è solo un placeholder.. ovvero una predisposizione alla creazione vera e propria

Creazione Node Agent

Da linea di comando digitare:

asadmin create-node-agent nodoDAS

nodoDAS è il nome che si è scelto per il node agent presente sulla macchina DAS.
Con questo comando viene creato un node agent sulla macchina DAS.

Una volta creato deve essere avviato con il seguente comando:

asadmin start-node-agent nodoDAS

Creazione Cluster

Da pannello adesso si procede con la creazione del cluster.

Andare sull'icona Clusters e cliccare sul buttone new per creare un cluster.


Riguardo la configurazione che avrà il cluster lasciando le opzioni su "Configuration" inalterate si creerà una copia della configurazione
default-config, il sistema chiamerà tale copia "cluster-config". Da questo momento sarà possibile configurare diversamente ciò che riguarda il cluster differenziandolo da ciò che riguarda l'istanza stand-alone agendo sulle diverse configurazioni.

Creazione istanza

Una volta creato il cluster si  procede aggiungendo la prima istanza e associandola al nodoDAS.
Si chiami tale istanza istanzaDAS.
Al fine di procedere con la creazione cliccare sul cluster appena creato (si trova all'interno della voce Clusters, nell'immagine precendete ne esiste già uno chiamato cluster), cliccare successivamente sul tab Instances e poi su New.
Indicare il nome instanzaDAS e associarla al NodeAgent nodoDAS dopo cliccare su ok.

Si è appena creata un istanza associata al nodo precedentemente creato, di default ad ogni stop and start del nodo corrisponderà analoga operazione sull'istanza creata.

Stato del Cluster

Facendo un riepilogo su ciò che finora è stato realizzato, ci ritroviamo con una macchina che funge da DAS sulla quale c'è il nodeAgent principale che controlla una sola istanza(instanceDAS).


Aggiunta Secondo Nodo

Per dare un senso al cluster si aggiunga un secondo nodo.

Nota: non è necessario il supporto cluster su questa seconda macchina.

I passi necessari per raggiungere questo obiettivo sono:

1) creare il node agent

usare il comando asadmin sulla macchina sulla quale vogliamo creare il secondo nodo:

asadmin create-node-agent --host macchinaDAS nodo1

il comando è equivalente a quello usato per creare nodoDAS ma questa volta si devono aggiungere dei parametri per indicare alla funzione di creazione(create-node-agent) del nodo agent che la macchina sulla quale risiede il DAS non è localhost(valore di default) ma è un altra macchina.
Nel comando usato si suppone che la macchina sulla quale è installato il DAS abbia come hostname macchinaDAS.

NOTA BENE: E' consigliabile usare un hostname piuttosto che il numero ip, le api jmx potrebbero creare qualche problema.
Non dimenticare su linux di modificare il file /etc/hosts/ con l'hostname scelto.

NOTA: Quando viene richiesto admin user name e admin password durante la creazione del nodo immettere le credenziali relative al login su DAS.

Il nodo creato è stato chiamato nodo1.

2) avviare il nodo

lanciare dalla console della macchina con il nodo1 il comando

asadmin start-node-agent nodo1

in modo da avviare il nuovo node agent.


3) creare l'istanza1 sulla macchina con nodo1

Tale operazione può essere eseguita invece dal pannello.
Andando sul cluster e aggiungendo come fatto precedentemente per instanzaDAS una nuova istanza associandola al node agent nodo1.

l'istanza creata la chiamiamo istanza1

4) avviare istanza1

Cliccare su cluster, cliccare su istanza1, cliccare su "start instance".


Adesso abbiamo due macchine

macchina DAS: con il DAS, un istanza (istanzaDAS), il node Agent principale (nodeAgentDAS).
macchina 1: con un instanza (instanza1), il node Agent corrispondente nodo1.

Avviare il Cluster

Operazione fattibile dal pannello del DAS.

Cliccare su cluster e su "Start Cluster".

Testare Il Cluster

Per testare il cluster è possibile usare un'applicazione di esempio fornita con il glassfish stesso.
Il file ear dovrebbe risiedere all'interno della cartella samples/quickstart/clusterjsp.

Effettauare il deploy dal pannello prestando attenzione al target sul quale si installa l'applicazione.
Bisogna rimuovere il target server e aggiungere invece il target cluster.

Selezionare il flag Availability nel caso in cui l'applicazione faccia uso delle sessioni e tali sessioni devono essere replicate nei diversi nodi del cluster.

Se tutto è andato bene l'applicazione dovrebbe risultare installata su entrambe le macchine.
Per verificare ciò digitare sul browser il seguente url:

http://localhost:38080/clusterjsp

sia dalla macchina DAS che dalla macchina 1.

NOTA: Come è possible notare dall'url le istanze del cluster ascoltano sulla porta 38080 e non su 8080. Su 8080 invece è in ascolto l'istanza standalone dell'application server che nonostante il cluster resta comunque funzionante. Ovviamente se non necessaria è possibile fermarla e usare solo le istanze configurate all'interno del cluster.



Link:


Il design pattern MVC in Java EE

MVC - Java EE

Introduzione

MVC è un design pattern(una soluzione progettuale generale ad un problema ricorrente) molto utilizzato nella progettazione del software.
MVC Stà per Model Controller View
.
MVC quindi è realizzato attraverso 3 componenti:

  • il model contiene i dati e fornisce i metodi per accedervi;
  • il view visualizza i dati contenuti nel model;
  • il controller riceve i comandi dell'utente (in genere attraverso il view) e li attua modificando lo stato degli altri due componenti

Questo pattern garantisce la suddivisione tra logica di business(gestita dal model) e interfaccia utente(gestia da view e controller).

Volendo applicare tale pattern alla tecnologia Java EE è possibile utlizzare le seguenti tecnologie java applicandole ai vari componenti del pattern.

Model: Tale componente può essere implementato attraverso gli entity bean, e i session bean
Controller: Esso può essere implementato mediante delle servlet.
View: Quest'ultimo attraverso jsp e/o jsf.

Gli entity bean quindi saranno un astrazione per rappresentare i dati, i session bean potranno effettuare delle operazioni sugli entity,
le servlet raccoglieranno l'input dalle jsp (utente) per effettuare richieste ai session bean e comunicare i risultati alle jsp e così via dicendo.

Esempio:

Supponiamo di dover realizzare un'applicazione web che permettare di visualizzare/modificare i dati di una tabella "utenti" presente in un db.

La tabella:Utenti
Le colonne: id, nome, cognome

Inseriamo all'interno della tabella una riga in modo da avere di default almeno un utente.

Supponiamo di utilizzare un persistence provider, ad esempio hibernate
Per tale entità(tabella utenti) è possibile creare un entity bean.
Creaimo inoltre un session bean dotato di entitymanager che realizza i metodi "edit" e "find".

  • edit - dato un entity di tipo utenti effettuera l'update rispetto al database usando il metodo merge dell'entitymanager.
  • find - dato un id, restituisce l'entity bean che rappresenta i dati in tabella che si trovano nella riga con id indicato.
  • .. è possibile implementare anche i metodi "create", "erase" per completezza.

Implementando questa porzione di progetto, si ottiene il componente "Model"

Implementiamo una servlet, (la servlet utente) che richiama mediante la resource injection, @EJB, il session bean.
Quindi dalla servlet richiamando il model e usando il metodo find(1) è possibile ottenere il corrispettivo entity contente i dati dell'utente con id = 1;

Se invece la servlet riceve i parametri GET o POST "id", "nome" e "cognome" allora effettuerà l'aggiornamento sul db, creando un nuovo entity con i dati passati tramite parametri http e richiamando il metodo edit del session bean.
(Nota che quando gli entity abbandonano le componenti ejb, ovvero vengo usati ad esempio, da componenti web, entrano nello stato un-managed..)

La servlet in questo caso realizza il controller.

La servlet in questione setta nell'oggetto request l'attributo "utenti" settando l'istanza utente ottenuta dal session bean e usando un RequestDispatcher effettua un forward verso una jsp che si occupa di mostrare una form html tale da permettere la lettura e la modifica dei dati dell'utente.
La modifica avverà richiamando la servlet utenti di partenza passando opportunamente i rispettivi valori.

Questo breve articolo non ha la presunzione di essere esaustivo, in quanto entrano in gioco diversi concetti e tecnologie.. può comunque costituire punto di partenze per un approccio a MVC  a Java EE.







Java vs Php - una mia opinione

Java Vs Php

(articolo risale al 2008) 
Dovendo realizzare un progetto web, quale piattaforma scegliere?
La risposta è: "Dipende!".
Innanzitutto il confronto dovrebbe essere più specifico, dovremmo chiederci Java EE o Php?
E forse pensandoci un pò meglio dovremmo identificare all'interno di Java EE la sottotecnologia confrontabile con Php ovvero JSP.
Io personalmente dovendo realizzare un piccolo progetto, ovvero pochi script che dovrebbero girare su un web server veloce e leggero opterei per php, viceversa qualora dovessi realizzare un progetto "enterpirse" scegliere senza ombra di dubbio java ee.
Innanzi tutto pensando di utilizzare il paradgma di programmazione che và per la maggiore, ci troviamo di fronte da una parte Java che nasce come linguaggio di programmazione object oriented e dall'altra Php che diventa object oriented nella versione 5, trascinando ancora alcuni concetti di programmazione procedurale.
Ad esempio, se volessimo conoscere l'ip del client che stà contattando la pagina web, in java dovremmo chiamare il metodo dell'oggetto HttpRequest (quindi il dato ip viene incapsulato e trasportato all'interno di un oggetto) in php dobbiamo ancora chiamare una delle variabili globali messe a disposizione dal modulo.
Poi, una cosa secondo me molto importante è l'ambiente di sviluppo: l'IDE.
Riguardo la piattaforma Java è molto più facile trovare degli ambienti di sviluppo che offrono una serie di feature non indifferenti.
Giusto per fare due importantissimi esempi, basti pensare al debugger o al profiler.
Certo in php è possibile trovare dei tool per effettuare, ad esempio il debugging, ma trovare tutto il necessario in un unico ambiente di sviluppo ai livelli di netbeans è difficile.
Altro punto a favore di Java è la grande varietà di sottotecnologie della piattaforma Java EE, giusto per fare una grande distinzione, abbiamo le JSP per generare la gui fondendo html e codice java, gli EJB per la logica di business(ottenimento e elaborazione dati ),e le servlet per realizzare l'elemento di coesione tra model e view. Quindi, se ad esempio, si vuole seguire il pattern MVC si hanno già delle linee che aiutano a realizzare del software ben strutturato.
In php è anche possibilissimo fare altrettanto, soprattuto nella ver 5, ma la piattaforma di certo non ti guida in questo.
Altro punto a favore di Java EE è la gestione dei web-service molto migliore rispetto a quella di php.
Basti pensare che le librerie soap di php, non provvedono ancora alla generazione automatica del wsdl(informazione verificata 2 mesi fà).
Ancora Java, per ciò che concerne l'interazione con i db, esistono diverse librerie (Hibernate, TopLink, Kodo, OpenJPA,..) per la gestione della persistenza dei dati.
E' possibile avere una visione ad oggetti di un database relazionale grazie al mapping O/R, avere una gestione automatizzata delle transazioni (committ e rollback), e la portabilità rispetto al dbms usato. Grazie al linguaggio, EJB-QL, infatti sono le librererie che si occupano della pesistenza a convertire le query nei vari dialetti (mysql, postgree, oracle, sqlserver, apache derby, db2..etc.).
A favore di php, c'è da considerare la velocità del deploy di un'applicazione web, basta infatti copiare gli script da aggiornare nella corretta directory, senza effettuare analisi, scompattazione di file jar, ear, war etc.
Per php è necessario un web server(Apache) a differenza di Java EE che spesso necessita di un Application server(Glassfish, JBoss, Geronimo, etc.), in tal caso il server è molto più snello e veloce per php, garantendo migliori performance e tempi di riavvio.
Certo quest'ultimo è un confronto poco significativo in quanto si dovrebbe confrontare tomcat e apache.. ma volendo sfruttare a pieno le potenzialità della piattaforma Java EE(che non siano solo servlet e Jsp) la scelta ricade su un application server con le conseguenze di cui parlavo.
Altro punto a favore di php, è la maggiore rapidità con la quale si impara. Java EE è più vasto e mette a disposizione diverse sottotecnologie quindi richiede dei tempi più lunghi per impare a scegliere e usare le varie componenti.
Anche la documentazione è più ostica per Java (parlo dei javadoc) rispetto ai phpdocs, ma ciò è dovuto alla conformazione ad oggetti del linguaggio e relative librerie di java.
Se la scelta, php-java la dovessi effettuare a prescindere dal progetto, e quindi dai requisiti del software richiesto, investirei su Java.
Sia perchè nel mondo del lavoro, lo sviluppatore Java è pagato meglio, sià perchè investendo su Java si investe automaticamente su una tecnologia presente non solo sul web ma anche su applicazioni desktop, mobile, etc. etc.
Inoltre è anche possibile usare entrambe le tecnologie, in grosso progetto ad esempio si potrebbe usare Java EE per la logica di business, e php per il frontend.
Vorrei concludere dicendo che, con entrambe le soluzioni si può sviluppare quasi ogni tipo di progetto web, ovviamente la cosa più importante è la buona progettazione del software.
Forse ho scritto questo articolo solo per portare un pò di gente sul mio blog!!!