Newsgroup: it.comp.java
Titolo: java & il buffering delle pagine jsp

Salve ragazzi.
Sto cercando un buon metodo per fare simulare il caching nelle pagine
JSP
di ResultSet da query su Oracle.
L'architettura che uso nell'app. è praticamente di tipo M1:
pag. JSP<-->beanPage(.<-->..)
La tecnica che ho visto in giro + diffusa è quella di
- mantenere  tanti arraylist nel bean principale quante sono le colonne
della result
- gestire il primo record della pagina corrente, per gestire
paginazioni.
Oramò, anche se funziona sta cosa è UN CASINO .
E lo è ancora di + dal momento che in molti casi ho bisongo
di elaborare opportunamente risultati di molte colonne.
Quel che mi viene in mente per ovviare a tutto questo
- anche per snellire il codice delle pagine -
è di costituire una sorta di wrapper del ResultSet
che mi permetta
- gestire dai e metadati del Reslulset in maniera + efficiente
(tanto + che è abbastanza semplice generare una sorta di 'paginazione'
già a partire da Oracle con i parametri sugli Statement)
- di generare magari HTML e di gestirlo meglio..
Datemi qualche idea, anche perchè
ArrayList di ArrayList (oppure arraylist di Oggetti a n di campi
dinamico, che è la stessa cosa ), non mi sembra il caso...
PS:   peace

dinamico, che č la stessa cosa ), non mi sembra il caso...
Se non voi usare il ResultSet direttamente le possibilita' sono:
ArrayList di ArrayList: una schiefezza.
ArrayList di Map: molto meglio
ArrayList di Object: ottimo.
E come mai non ti sembra il caso? 

Perchè sarebbe
- ottimo nel contesto della pagina: voglio dire che nella pagina saprei
tutto dei metadati della query.
- inefficiente nel contesto generale: dovrei in pratica mantenere un
tipo di Oggetto, con i campi relativi ai metadati della query, uno per
ogni resultset che mi serve.
Una proliferazione pazzesca.
E qui la necessità di generare dinamicamente arraylist (e finqui va
bene) di ... arraylist (o qualcosa cmq di 'dinamico'): e s'alza
l'impigo di risorse e il server andrebbe abbastanza apalla.
E questo anche se gestissi questa sorta di 'DataSet' paginando i
risultati a partire dall'SQL stesso (e Oracle devo dire in questo è di
ottimo aiuto), limitando dunque la mole di dati.
A questo punto sto valutando la possibilità di gestire un wrapper del
ResultSet stesso...
che mi dite?

Una proliferazione pazzesca.
Se e' vero che hai bisogno di decine e decine di oggetti, forse il progetto 
non e' un progettino tanto piccolo, motivo in piu' per fare le cose 
decentemente.
Gli oggetti descrivono il tuo dominio applicativo, e lo descrivono una volta 
per tutte (refactory a parte ovviamente).
Mi sembra molto peggio invece inventarsene uno per ogni pagina, anzi per 
ogni query.
Ricordarsi tutti i campi ogni volta, i loro nomi o i loro indici, non mi 
sembra assolutamente una soluzione pulita...quello si che e' una 
proliferazione pazzesca di codice inutile. ;)
Se lavori ad oggetti ad esempio puoi crearti una classe di utility che ti 
restituisce la lista di oggetti per quella query. Ad esempio:
class UserUtil {
  public static List<User> getUsers() {
      //fai qua la querty e ritorna la lista di user
  }
  public static User getUserById(Long id) {
    //ottienu un User da un id
  }
  public static User login(String username, String password) {
    //controlla se esiste un utente con quel username/pwd e ritornalo
   //altrimenti ritorna null
  }
  public void saveUser(User user) {
    //salva un nuovo utente
  }
}
Nella JSP poi basta che richiami il metodo di UserUtils che vuoi, e basta.
Un ulteriore vantaggio e' che puoi usare JSTL o comunque il supporto che le 
JSP hanno per i bean.
Infatti saprai che non serve usare gli scriptlet per stampare una proprieta' 
di un bean:
<html>
L'utente e' :  <span class="usernameLabel"><c:out 
value="${user.username}"/></span>
</html>

restituisce la lista di oggetti per quella query.
E' esattamente la strada che ho intrapreso.
In pratica per ogni pagina gestire un tipo di oggetto che caratterizzi
uno (o anche + wrapper di resultset, o cache) è inpensabile per i
motivi che hai esposto.
Però effettivamente gestisco per ognuna una classe di utility che
mi gestisce le sql per quella pagina (restringo in pratica le
rischieste al contesto logico della pagina), delegando poi un secondo
oggetto, magari globale di eseguire poi quell'sql.
I result set dunque visibili nel 'bean principale' sono utilizzabili
nella maniera + opportuna
(tra i tools ho messo su per esempio una funzioncina statica che mi
'spara fuori' l'html di una combobox a partire da un resultset e dunque
in jsp mi basta richiamare quel metodo con gli opportuni parametri..)
In questo modo tra l'altro si riesce perfettamente
a tenere traccia (e a gestire) errori, eccezioni e  quent'altro.
L'unica cosa che mi indispettisce d'atra parte è proprio la gestione
di un Resultset
all'interno del bean pricipale della pagina, riguardo per esempioo la
generazione delle paginazioni, oppure la predisposizione dello stesso
ad eventuali altre trasformazioni
(le nformazioni per decifrare per esempio il valore di un campo
risultato di una query le ottengo interrogando in diversi passi il
db...)
Mi chiedo se c'è una maniera  meno 'scolastica' (e + efficiente) di
quella che ho trovato 
per gestire questa serie di problemi.

ad eventuali altre trasformazioni
Purtroppo non ho afferrato cosa sia il "bean principale" quindi non posso 
dirti molto.
Tuttavia gia' il fatto che tu lavori con i ResultSet dentro la JSP, 
significa che devi chiuderli e gestire tutte le eccezioni di tipo 
SQLException del caso, e questo per ogni pagina: pagina incasinata e 
mantenibilita' a rischio.
Per questo la cosa migliore sarebbe quella di svolgere completamente le 
query dentro i metodi delle classi di utility, e di chiudere la' le 
connessioni, Statement e ResultSet.
Nella JSP a questo punto non devi fare altro che richiamare i metodi e 
visualizzare i dati.
E' per questo che il tipo di ritorno dei metodi non dovrebbe essere di "tipo 
JDBC" (ResultSet ad esempio), ma qualcosa del tuo dominio applicativo 
(List<User>) , oppure una java.util.Map (o List<Map>). 

SI scusa, non mi son spiegato bene.
Intendo per 'beanPrincipale' (e sicuramente si chiamerà in un'altra
maniera)
il bean, o comunque la classe che si occupa di gestire la logica di
esecuzione (il business logic insomma, il secondo livello applicativo)
della pagina (l'ultimo livello, quello 'presentazione')
e di completare la logica di esecuzione nel contesto dell'applicazione.
Cioè JSP<->bean Pricipale <->(altri oggetti, utility etc..)
E' come ti dicevo un'architettura semplice ma che decentralizza
fortemente il controllo dell'applicazione intera, semplicità di
reaizzazione del contesto della pagina, ma complessità aggiunta a
livello globale (lo riconosco)
-- perchè? perchè Struts non me lo fanno usare!!! (!!!!!)
Nella pagina JSP  vorrei utilizzare il meno possibile scriptlet,
e infatti prima riferendomi ai combobox mi riferivo infatti a taglib
che ho preparato ad hoc...
la pagina gestisce solo parametri utili per la visualizzazione stessa,
insomma (tipo numero pagina, immagini , blocchi di codice) o al limite
looping su set di dati.
Ora è proprio questo il punto:
premesso che la pagina non sanno nemmeno cos'è un Resultset,
potrei trovare una maniera per gestire questi resultset in maniera più
efficiente
nel bean che ralizza la logica della pagina,
soprattutto riguardo a problemi come paginazione e ad eventualità come
il riuso di resultset per operazioni successive (ma sempre nel codoce
del bean)?
Ora cme ora la soluzione più smplice per luna pagina che interroga un
db su un insieme di dati (una pagina di visualizzazionem insomma),
non fa altro che
1. validare l'input dei parametri di ricerca
2. passare i parametri al refacory di SQL (...)
3 eseguire la query
4 memorizzare in un set di ArrayList il risultato
5 l'accesso ai record viene dunque permesso con i metodi get del bean
su un oggetto 'buffer' , sempre in detto bean
ciclando di volta in volta du gli indici degli arraylist
Va da se che la paginazione funziona in maniera veloce si, ma
sicuramente nefficiernte per  gestione dell'insieme dei dati.
Insomma la classica soluzione 'scolastica'.
E questo non va bene.
Ora, localizzando il problema,
la produzione non si è frmata, ma
il problema rimane, a mio avviso.

del bean)?
Quindi stai chiudendo i resultset, connessioni etc dentro i metodi di 
utility? cosi va bene ;).
Per quanto riguarda il caching puoi sempre fare la query una volta, e 
salvarla in sessione.
(basta salvare l'array in sessione). Quando un utente si sposta da una 
pagina all'altra prendi una parte dell'array che sta in sessione e lo copi 
in request. Nella JSP visualizzi solo quest'ultima porzione.
Ora questo va bene perche' riduce il numero di query da fare, ma impiega 
molta piu' memoria (devi tenere un oggetto di grosse dimensioni in 
sessione).
Se le query restituiscono pochi oggetti allora va benissimo anche cosi (e se 
gli utenti non sono a migliaia al minuto).
Altrimenti molto meglio fare la query di volta in volta e affidarsi alle 
prestazioin di Oracle (che sono sicuramnete elevate ;)..).
Comunque ribadisco che ti conviene usare una lista di oggetti. Quello che 
fai tu non e' certo una "best practice". 

fai tu non e' certo una "best practice".
Eh... me ne rendo conto
e me ne renderò conto soprattutto qando avrò a che fare con
result set da una decina di colonne.
ti lascio immaginare il codice...
L'dea  della lista di oggetti map d'altra parte mi sembra molto buona.
E se lavoro poi su  recordset
gestiti ad esempio :
// ...
Statement statement = getConnection().createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY);
ResultSet result =
    statement.executeQuery("SELECT name, office FROM employees");
// Jump to first record, and retrieve only some records
result.absolute(firstRecord);
result.setFetchSize(recordsPerPage);
this.employees = new ArrayList();
while(result.next()) {
// ...
con le dovute precauzioni sulla modifica dei dati su db
(il codice l'ho preso da un articolo che ti segnalo subito:
https://bpcatalog.dev.java.net/nonav/webtier/db-navigation/index.html
)
forse che forse potrei pure limitare l'impiego di risorse, magari.
Metto su un oggetto che gfestisce opportunamente una list<map>
magari con i dovuti metodi di accesso..
Che dici?

Che dici?
Dico che se avevi le tue classi di utility puoi usare quelle e non ti serve 
fare niente di partiolare.
Segui piu' o meno l'esempio del metodo
public class EmployeesUtility {
  public List getEmployees() {
  ...
  }
}
del tuo articolo.Ad esempio modificalo per accettare un numero di 
pagina:public List getEmployees(int page) {..}Aggiungo 2 cose:-cerca di 
usare le PreparedStatement, soprattutto nelle query SQL di scrittura.-il 
codice di presentazione va nelle JSPs, il codice di logica nelle servlet. 
(magari lo fai gia'..) 

con le dovute precauzioni sulla modifica dei dati su db
no scusa, mi sono incasinato: intendevo dire la formattazione dei dati
che ricevo DA DB
(modifica è stato un po' sconveniwente e fuorviante, sorry)

Ma spero di aver capito male a sto punto
Semmai una riga della query solitamente puo' essere mappata sull'oggetto 
Employ.
Secondo me sei troppo legato al DB.
Quando progetti un'applicazione non si dovrebbe tenere in considerazione il 
db fino a che non si arriva a dover persistere i dati. Vedi che sollievo se 
fai cosi'.
Se anche dentro un metodo devi fare la join non capisco il problema.
Non cambia nulla, ritorni sempre un'entita' oppure una lista di entita' 
(mappe o oggetti che siano). Il fatto che questa, per come e' organiazzato 
il db, sia il risultato di un'operazione di JOIN a te non dovrebbe fregare 
proprio niente.
Anzi te ne devi interessare solamente dentro il metodo che implementa la 
questione delle persistenza di quel' entita'.
Cioe':
public class EmployeesUtils
public List<Map> getEmplyess() {
 .... //per come e' organizzato il db ti serve una JOIN
}
servlet:
List<Map> employees = new EmployeesUtils().getEmployees();
request.setAttribute("employees", employees);
...
jsp:
<c:forEach value="${employees}" var="emp">
..
</c:forEach>
va be le JSTL non le ricordo, sono andato a caso con quel tag ;)
Comunque come vedi, dentro il metodo
getEmployees()
 puoi avere fatto quello che ti pare: join non join, anche distrutto 
l'universo nel frattempo, ma agli altri livelli dell'applicazione non gliene 
frega niente. E' solo un dettaglio implementativo.
Addirittura alcune volte in fase di sviluppo mi sono ritrovato a creare dei 
metodi come getEmployees totalmente fittizi, che ritornavano una lista di 
oggetti creati al volo (senza leggere il db). Poi dopo aver condiderato la 
persistenza dei dati, costruito il db ecc, tornavo su quel metodo e lo 
riscivevmo in modo da ottenere i dati dal db.
Il DB in sostanza e' solo un dettaglio (un dettaglio importante certo), e 
non deve essere il perno su cui l'applicazione si sviluppa.

aspetta un attimo
e vediamo se ho capito:
esattamente come dici tu
son convinto che bisogna muoversi nel senso di rendere
il meno possibile influente la dipendenza fisica dell'applicazione
(DB e moduli logici il + distaccati possibli, insomma).
La mia idea sarebbe in pratica quella di gestire
un oggetto, chiamiamolo A, che mantenga un ArrayList di mappe (proprio
map ) costruite dinamicamente sulla query che eventualmente eseguo, e
quindi sul resultset
Prevedere per A dei metodi di accesso opportuni.
E a seguire un metodo opportuno per la paginazione, tipo quello che hai
esposto prima.
Così si che me ne fregherei altamente del DB, (query a parte,
s'intende)
Quanto a prestazioni su sto metodo mi sto regolando un po' sulle
informazioni che
trovato su
http://www.oracle.com/technology/pub/articles/maps1.html
sembra che quanto a prestazioni potrebbe andare...

esposto prima.
E' buona norma separare queste 2 cose.
Gli oggetti che costituiscono il dominio applicativo non hanno solitamente 
metodi di accesso ai dati. Questdi metodi di accesso vanno invece dentro le 
classi predisposte per la persistenza.
Quindi non mi piace questo:
public class A {
  private List list = new ArrayList();
  public void getList() {
    //query ecc
  }
}
Mi piace invece questo:
public class A {
  public  List get getList() {
  }
}
//siamo in una servlet
List list = new A().getList(); 

Mi trovi pienamente d'accordo.
Dopotutto quel che cerco di ottenere è
non solo un oggetto diciamo 'cache' a livello codice,
ma soprattutto una factory per generarlo nella maniera opportuna
Perfetto.
Davvero grazie.
La cosa che mi dispiace è quella che
si ha sempore poco tempo per parlare di questini 
di questo tipo.