Java installer … how to?
Mi sono trovato recentemente a dover distribuire, in serie, ed ad un’utenza particolarmente non specializzata un’applicazione gestionale desktop, sviluppata in Java, che utilizza MySQL per la persistenza dei dati. La difficoltà principale è gestire, in modo semplice nei confronti dell’utente finale, l’installazione di tutte le componenti software necessarie al funzionamento dell’applicazione. L’ideale, in questi casi, è riuscire a sviluppare un installer eseguibile che richieda semplicemente il doppio click all’utente, preoccupandosi in background di tutte le operazioni la cui configurazione porrebbe difficoltà apparentemente insormontabili.
Nel mio caso i requisiti per l’installer da sviluppare erano:
- funzionare su Windows XP/Vista/7
- funzionare in assenza di JRE
- installare MySQL Server in modo silent
- installare una versione del JRE specifica con librerie native per la comunicazione su porta seriale RS-232 (Java Communication API)
- caricare lo schema del DB e svolgere operazioni su di esso
- creare gli opportuni launcher per l’utente (esecuzione automatica, collegamento sul desktop, etc)
Quando la probabilità di richieste concorrenti al RDBMS è bassa (design almost-single-thread), oppure non ci sono particolari vincoli “real-time” il ricorso ad un DB-in-a-file (come ad esempio SQLite) può essere la soluzione migliore e più pulita perchè non richiede l’installazione di nessuna componente software di terze parti, permettendo di distribuire semplicemente una libreria insieme alla nostra applicazione (a questo scopo in Java ho utilizzato diverse volte con soddisfazione questa libreria).
Purtroppo in questo caso l’utilizzo di SQLite poneva dei limiti prestazionali a causa del particolare design dell’applicazione e questo mi ha obbligato a dover disporre di un MySQL Server, complicando non poco sia la scelta che l’implementazione del sistema installer.
Free or commercial?
Una semplice ricerca per “java application installer” ed un paio di ore di lettura di vari post sull’argomento consentono sostanzialmente di…..generare più confusione di prima, ma creano la certezza che intorno a questo tema si sia sviluppato un mercato di prodotti commerciali che consentono di ottenere installer esteticamente gradevoli in un tempo anche abbastanza veloce (dopo qualche prova il migliore per rapporto qualità/prezzo mi è sembrato essere questo).
Per le operazioni complesse (come l’installazione silent di MySQL Server o le susseguenti azioni sui database) in ogni caso è necessario affidarsi a scripting di qualche tipo. Pertanto, visto che nel mio caso l’estetica dell’installer non era un requisito primario, e che risparmiare non fa mai male, mi sono orientato verso soluzioni freeware che, rinunciando a qualcosa sul lato grafico, offrissero comunque sistemi di scripting potenti.
Dopo alcune prove la mia scelta è ricaduta su NSIS Nullsoft Scriptable Install System, un sistema professionale per lo sviluppo di installer destinati a Windows, basato su un linguaggio di scripting particolarmente versatile ed in grado di rendere possibile l’implementazione dei task più complessi nel processo d’installazione. Il sistema è molto noto perchè utilizzato per la creazione di installer che tutti abbiamo usato almeno una volta, come ad esempio quello WinAmp o del famoso software P2P eMule.
A lovely coding experience with elements of PHP and assembly
Il primo impatto non è dei più semplici, la sintassi è abbastanza ostica, ma la documentazione estensiva, ed un po’ di pazienza rendono in grado chiunque di creare un installer efficiente ed affidabile.
L’utilizzo dei registri in stile assembler può lasciare un po’ perplessi ma una volta che ci si è presa la mano (contando soprattutto sulle decine di esempi presenti nei tutorial) è abbastaza facile districarsi fra i vari Push e Pop.
Il mio suggerimento è quello di partire da un esempio e di modificarlo secondo le proprie esigenze. In particolare sotto ci sono alcuni frammenti di codice NSIS che consentono di eseguire alcuni dei task più complessi che mi sono trovato ad implementare. Ho personalmente testato queste soluzioni su Windows XP, Vista e Seven in versioni a 32 e 64 bit.
MySQL Server silent install
Questa operazione è di gran lunga la più importante che il mio installer compie sul sistema ospite. In pratica, all’insaputa dell’utente, e senza richiedere nessuna configurazione, l’eseguibile distribuito deve installare una specifica versione del MySQL Server ed inserirlo fra gli elementi avviati automaticamente al boot della macchina.
A questo scopo e necessario:
- disporre di un installer MySQL per il sistema target (download)
- sapere come inserirlo come risorsa all’interno del nostro installer
- eseguire l’installer MySQL tramite il nostro installer NSIS
file mysql5.1.53.msi ExecWait 'msiexec /i "$INSTDIR\mysql5.1.53.msi" /qn INSTALLDIR="$PROGRAMFILES\MySQL\MySQL Server 5.0\" /L* "$INSTDIR\MSI-MySQL-Log.txt"' ExecWait '"$PROGRAMFILES\MySQL\MySQL Server 5.0\bin\mysqlinstanceconfig.exe" -i -q ServiceName=MySQL RootPassword=xxx ServerType=DEVELOPMENT DatabaseType=MIXED Port=3306 RootCurrentPassword=xxx'
La direttiva file è molto importante perchè ci permette di dichiarare le risorse che NSIS dovrà includere nel nostro installer, in modo che siamo disponibili per le operazioni sul sistema target una volta che l’utente ha avviato l’eseguibile. In questo caso ho incluso un installer di MySQL Server 5, prelevato direttamente dal sito ufficiale. Va da sè che l’installer deve essere appropriato al sistema target (32 o 64 bit).
Una volta dichiarata l’inclusione della risorsa la direttiva ExecWait permette di eseguire qualsiasi comando di sistema, un po’ come se si digitasse direttamente sul prompt. Nel mio caso sto chiedendo alla macchina target di avviare il processo di installazione tramite file msi specificando anche:
- /qn per evitare qualsiasi interattività
- INSTALLDIR per specificare dove installare il prodotto
- /L* per specificare un livello di LOG alto sul file specificato
ExecWait non ritorna fin quando il sistema è occupato dall’esecuzione del comando passato come argomento. La seconda chiamata di questa direttiva server per configurare il MySQL Server appena installato, utilizzando una utility inclusa nel primo installer, ovvero mysqlinstanceconfig.exe. Anche in questo caso i parametri -i e -q garantiscono che nessuna richiesta di informazioni venga presentata all’utente, che al termine del processo si ritrova ignaro possessore di un MySQL Server.
Ricerca ed installazione JRE
Altro prerequisito molto importante da verificare è la presenza di una JRE. Sul sito di NSIS ci sono diversi tutorial interessanti che automatizzano la ricerca di un JRE in modi diversi.
Il più semplice, ma funzionante in una buona percentuale dei casi è questo, altrimenti, se si desidera un processo di ricerca più completo, si può optare per la modifica (in realtà abbastanza complessa) di un secondo script.
Ad ogni modo, può essere utile fornire una modalità interattiva che scarichi ed installi automaticamente, la versione del JRE più indicata per la nostra applicazione. In nostro aiuto viene questo spezzone di codice:
;-------------------------------- ; Definitions for Java 1.6 Detection !define JRE_VERSION "1.6" !define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=45832" ;-------------------------------- Function GetJRE MessageBox MB_OK "YourAppName uses Java ${JRE_VERSION}, it will now \ be downloaded and installed" StrCpy $2 "$TEMP\Java Runtime Environment.exe" nsisdl::download /TIMEOUT=30000 ${JRE_URL} $2 Pop $R0 ;Get the return value StrCmp $R0 "success" +3 MessageBox MB_OK "Download failed: $R0" Quit ExecWait $2 Delete $2 FunctionEnd
La costante JRE_URL è il link da cui scaricare la versione di JRE da installare sul sistema target, mentre la funzione GetJRE si preoccupa di visualizzare un box informativo e scaricare, tramite la macro nsisdl::download, l’eseguibile per installare appunto il Java Runtime Environment. Senza entrare nel dettaglio di ognuna delle righe di codice sopra è interessante far notare la linea:
StrCmp $R0 "success" +3
Questo costrutto è un salto condizionato, in pratica dice che nel caso l’operazione di compare fra il contenuto del registro $R0 e la stringa “success” ritorni true si deve effettuare un salto di 3 linee per trovare la prossima istruzione da eseguire. Guardando lo spezzone di codice sopra si vede che la linea a cui si salta è la linea ExecWait $2 coerentemente con lo scopo dello script….in pratica “se il download è andato bene, esegui quanto scaricato”. Molto conciso (e illeggibile).
Esecuzione di queries MySQL
Giunti a questo punto dovrebbe essere abbastanza chiaro che il comando ExecWait consenta in pratica di invocare tutti quei comandi che si potrebbero digitare sul prompt. A questo scopo infatti è ad esempio possibile utilizzarlo per eseguire query MySQL sul database server appena installato:
ExecWait '"$PROGRAMFILES\MySQL\MySQL Server 5.0\bin\mysql" --user=xx --password=xxxx --execute="create database mtwsn104;"'
Creazione di shortcut
L’installer di solito si chiude con la creazione di tutti quei link che facilitano l’accesso dell’utente ai prodotti appena installati.
Nell’ordine questo spezzone di script provvede a creare:
- una cartella nel menu “Start”
- un link ad un unistaller
- un link al software installato
- un link nella cartella di esecuzione automatica ($SMSTARTUP)
CreateDirectory "$SMPROGRAMS\${MUI_PRODUCT}" CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\Uninstall.lnk" \ "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 \ CreateShortCut "$SMPROGRAMS\${MUI_PRODUCT}\${MUI_PRODUCT}.lnk" \ "$INSTDIR\YourProgram.exe" "" "$INSTDIR\YourProgram.exe" 0 CreateShortCut "$SMSTARTUP\YOURSERVICE.lnk" \ "$INSTDIR\YourService.exe" "" "$INSTDIR\YourService.exe" 0'
Altre risorse
Per creare il vostro installer NSIS non avete bisogno che di installare NSIS sul vostro PC Windows e scaricare un editor per file NSI. Io ad esempio ho utilizzato HM NIS EDIT, semplice, freeware e molto efficace.
Tutta la documentazione che serve la trovate sul sito ufficiale del progetto NSIS.
Una risposta su “Usare NSIS per distribuire applicazioni Java/MySQL”
Ottimo articolo! E’ proprio ciò di cui avevo bisogno. Grazie mille.