|
Introduzione
Niente resiste all'uso prolungato. A volte nemmeno
all'uso breve e sporadico. L'editor CMSApplet
appartiene alla seconda categoria. Nella versione
precedente l'applet CMSApplet possedeva la capacità
di caricare un testo XML, corrispondente al corpo
ed alla bibliografia di un articolo. In seguito
è emersa la necessità che l'applet
potesse essere direttamente inizializzato usando
un testo XML. L'introduzione di questa possibilità
ha fatto emergere alcuni presupposti impliciti
del parser XML. Superfluo ricordare che, in programmazione,
un presupposto implicito sia la radice di ogni
bug. Vediamo prima l'introduzione del caricamento
in fase di inizializzazione, poi la soluzione
dei bug emersi con la nuova caratteristica.
Inizializzazione
con un documento XML
Un Applet Java può ricevere dei valori
di inizializzazione, incapsulati in parametri
contenuti nella pagina HTML che inglobi l'Applet.
Nell'uso più comune questi parametri sono
stringhe di testo, colori, o numeri. Il Content
Management System richiede invece che ad un Applet
riceva un intero documento XML. Non essendo pensabile
l'incapsulamento di un intero documento XML in
un parametro html, abbiamo pensato di usare come
parametro per l'Applet un URL che puntasse ad
una risorsa web in grado di fornire il contenuto
dell'articolo, in formato XML. Richiedendo l'Applet
non solo il contenuto, ma anche l'identificatore
dell'articolo, al parametro URL si è aggiunto
un parametro che contenesse, appunto, l'ID dell'articolo.
Estrarre un parametro inviato all'Applet dalla
pagina HTML che lo contiene è questione
di poche istruzioni:
String
urlArt = getParameter("article-url");
String artid = getParameter("article-id");
Il
contraltare HTML di questi elementi è rappresentato
da opportuni TAG "param":
<param
name="article-id" value="CMSApplet"></param>
<param name="article-url" value="[url
costruito durante l'esecuzione]"></param>
Ottenuti,
durante l'inizializzazione e dunque nel metodo
istanza "init()", l'URL e l'ID dell'articolo,
l'Applet altro non fa che leggere il dati da un
flusso, restituito da un oggetto java.net.URL,
traducendo i byte in caratteri. Dopo aver ricostruito
interamente il testo, è invocato il metodo
di istanza "setText(String doc, String id)".
Abbiamo discusso di questo metodo nell'articolo
precedente, a cui pertanto rinviamo.
Content
is not allowed in prolog?
Il caricamento di testo dal flusso ricavato da
un URL è, in Java, un procedimento assolutamente
elementare. Un oggetto java.net.URL è in
grado di restituire un java.io.InputStream che
consente di leggere, byte per byte, il contenuto
della risorsa a cui l'URL punti. L'architettura
"pipe" del sistema di Input / Output
di Java fa il resto. In particolare, uno dei modi
più semplici per leggere dei caratteri
da un flusso InputStream consiste nel creare uno
StringBuffer ed un BufferedReader. Il BufferedReader
legge valori interi dal flusso sottostante, e
quegli interi corrispondono ad altrettanti caratteri.
Aggiugendo allo StringBuffer i caratteri così
letti si ottiene una lettura tutto sommato efficiente,
per documenti di media dimensione (~1mb). Durante
la prima stesura del codice chi scrive è
incappato in una svista. Un BufferedReader legge
interi. Prima di essere aggiunti allo StringBuffer,
quegli interi devono essere convertiti in valori
char. La conversione è stata omessa per
errore. Poiché uno StringBuffer accetta
indifferentemente qualsiasi tipo di dato, componendo
internamente il testo con una conversione di ciò
che gli sia passato in testo, il risultato era
un stringa di testo contenente i numeri interi
letti dal flusso. Qualcosa tipo: 15435097987...eccetera.
Inutile dire che questo non rappresenti un "documento
XML ben formato". Ricevendo questo testo
come corpo dell'articolo, il parser produceva
un errore. Mancando nella versione attuale dell'applet
un log dei messaggi d'errore, l'applet, pur ricevendo
un URL corretto sia dal punto di vista dell'indirizzo
che del contenuto del documento puntato, non mostrava
alcunché. Esaminando la traccia dell'errore
riprodotta sulla console Java, risultava un fantomatico:
content
is not allowed in prolog
rilasciato
dal parser SAX durante l'esecuzione del metodo
pushXML di FilteringOp. Questo messaggio è
rilasciato nel caso di una particolare malformazione
del documento XML. È il sintomo della presenza
di alcuni caratteri in eccesso prima dell'header
XML. Lascio alla vostra immaginazione quanto poco
intuitivo sia stato risalire da un messaggio che
tiri in ballo "prolog" ad un intero
non convertito in "char".
Da
una soluzione a molti problemi
Non tutto è andato liscio. L'invocazione
del metodo setText(String, String) da parte del
componente CMSApplet richiama il metodo "setArticle(String,
String)" di un oggetto ArticleEditor. Ricordiamo
che ArticleEditor è un tipo interfaccia
di cui, nel sistema attuale, esiste una sola versione
concreta, prodotta da un factory. Questa versione
concreta, SimpleArticleEditor, si appoggia, per
la traduzione di un testo XML in testo stilizzato,
ad un terzo componente, FilteringOp. Di FilteringOp,
in particolare, è invocato in questa fase
un metodo "pushXML" che riceve una corposa
stringa di testo ed un JTextPane. Il suo scopo
è riempire il pannello di testo del risultato
della trasformazione di un testo XML in testo
stilizzato. Il parser esegue un'operazione "bovina":
legge il documento XML e aggiunge letteralmente
linee di testo formattato al JTextPane. JTextPane
infatti possiede dei metodi brevi per inserire
linee di testo formattate, che rinviano internamente
a metodi paralleli di uno StyledDocument. Il metodo
più usato durante questo trasferimento
di testo è "jtextPane.replaceSelection(...)".
Il motivo risiede nella polivalenza di replaceSelection.
La sostituzione del testo è sostituzione
vera solo se esista una selezione corrente. In
caso contrario, il metodo realizza un inserimento,
attribuendo al testo inserito il formato di paragrafo
e di carattere valido per la posizione in cui
si inserisca il testo. L'inserimento avviene nella
posizione in cui si trova il carrello del pannello
di testo. Per un JTextPane, la posizione del carrello
è aggiornata automaticamente sull'ultimo
carattere del testo inserito, il che solleva dalla
necessità di definire una posizione di
inserimento, nel caso di una costruzione progressiva
del documento, come avviene nel metodo pushXML.
A patto che, e qui sta il presupposto implicito
citato nell'introduzione, il pannello sia visibile.
Nel caso in cui un JTextComponent non sia visibile,
infatti, la posizione del carrello non è
aggiornata. Da ciò deriva l'inserimento
di ogni linea di testo nella posizione zero del
documento. Comicamente, il testo del documento
appariva invertito. La soluzione al problema è
intuitiva. Visibile o non visibile, è sufficiente
aggiornare la posizione del carrello del JTextPane
nel punto desiderato, durante la composizione
del testo, con il metodo setCaretPosition degli
oggetti JTextComponent.
Conclusioni
Dalla prima versione dell'applet all'attuale l'editor
ha subito una caduta di prestazioni rilevante
durante il caricamento del testo. Al momento l'obiettivo
principale è scovare ed eliminare questo
decadimento. Non è un problema di FilteringOp,
la classe che trasforma il documento XML in documento
di testo. Il che è curioso, essendo questa
l'unica classe che effettivamente compia passi
rilevanti, in termini di quantità e complessità
delle istruzioni. Tra le molte new entry, la più
sospetta è l'introduzione di un UndoManager
per l'editor JTextPane. Il passaggio a FilteringOp
di un componente di testo per cui sia attivato
il meccanismo di undo-redo, unito alla costruzione
incrementale del documento, potrebbe in effetti
caricare il sistema della produzione di un elevato
numero di oggetti, destinati all'UndoManager.
Destinazione peraltro superflua, essendo il caricamento
di un nuovo documento l'atto distruttivo assoluto
per eccellenza. Che la soluzione stia effettivamente
in una sospensione temporanea del sistema di annullamento
e ripetizione delle azioni, è dimostrabile
unicamente attraverso la costruzione di micro
benchmark del sistema. Questo appartiene alle
prospettive del nostro editor di testo per il
Content Management System di MokaByte.
Bibliografia
[1] Gosling, Arnold, Holmes - "The Java Programming
Language, Third Edition", The Java series,
Addison Wesley, 2000
|