ACG Vision4 Service Bus

Transcript

ACG Vision4 Service Bus
ACG Vision4 Service Bus
Guida Tecnica
Componenti Architetturali
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 1 di 167
Quarta Edizione (16 Gennaio 2014)
Questa edizione si riferisce alla Versione 1 Rilascio 4 livello di modifica 0 di ACG Service Bus (5733-F13) e a tutti i
successivi rilasci e modifiche, se non altrimenti indicati in nuove edizioni o lettere di accompagnamento.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 2 di 167
Note e Trademarks
© Copyright ACG S.r.l. 2014. Tutti i diritti riservati.
ACG e ACG Vision4 sono marchi di ACG S.r.l., con socio unico e soggetta all’attività di direzione e
coordinamento di TeamSystem S.p.A., sede legale in in via Yuri Gagarin, 205 – 61122 Pesaro
(PU), Cap. Soc. € 100.000 i.v., codice fiscale e iscrizione al Registro delle Imprese di Milano n.
08419500965 (di seguito “ACG”) - Tutti i diritti riservati.
I marchi e loghi riportati nel presente documento diversi da ACG e ACG Vision4 (ivi inclusi, a mero
titolo esemplificativo e non esaustivo, IBM, il logo IBM, Adobe, il logo Adobe, PostScript, il logo
PostScript, Intel, il logo Intel, Intel Inside, il logo Intel Inside, Intel Centrino, il logo Intel Centrino,
Celeron, Intel Xeon, Intel SpeedStep, Itanium e Pentium, Linux, Microsoft, Windows, Windows NT e
il logo di Windows, UNIX, Java, Novell, il logo Novell, openSUSE e il logo openSUSE, AS/400,
BladeCenter, Cognos, DB2, DB2 Universal Database, eServer, i5/OS, iSeries, OpenPower, OS/400,
POWER, Power Systems, pSeries, Rational, System i, System i5, System p, System p5, System
Storage, System x, WebSphere, etc.) sono di titolarità di soggetti terzi. ACG rispetta i diritti di
proprietà intellettuale di terzi.
Tutti i contenuti del presente documento e i diritti ad essi correlati sono riservati. Tali contenuti
pertanto possono essere consultati esclusivamente per finalità d’informazione personale, essendo
espressamente vietato ogni diverso utilizzo senza il preventivo consenso scritto di ACG.
Sebbene sia stata usata ogni ragionevole cura nel raccogliere e presentare le informazioni contenute
nel presente documento, nessuna garanzia è prestata in ordine alla loro esattezza, completezza, utilità,
né ai loro possibili impieghi da parte degli utenti; è pertanto esclusa ogni responsabilità di ACG per
errori, inesattezze od omissioni relative a dette informazioni. I contenuti del presente documento sono
soggetti a continuo aggiornamento e sono da ritenersi puramente indicativi e suscettibili di eventuali
errori e/o imprecisioni.
ACG può introdurre miglioramenti e/o variazioni ai prodotti e/o programmi descritti nel presente
documento in qualsiasi momento e senza preavviso.
Il presente documento può contenere informazioni che riguardano programmi e propositi futuri, che
vengono descritti di volta in volta mediante l’utilizzo di termini come "attendersi", "stimare",
"prevedere", "prospettare" e "programmare". Tali dichiarazioni per loro natura non comportano alcun
impegno a carico di ACG, che pertanto non assume in relazione ad essi alcuna responsabilità di
realizzazione.
Qualunque riferimento a siti web diversi da www.acginfo.it è fornito a solo titolo esemplificativo e
non costituisce invito all’utilizzo e/o navigazione. I contenuti dei siti web referenziati non sono parte
dei prodotti ACG e il loro eventuale utilizzo da parte dell’utente è effettuato a suo esclusivo rischio.
Le informazioni relative a prodotti non ACG contenute nel presente documento sono fornite dai
rispettivi fornitori, dagli annunci pubblicitari e da informazioni liberamente disponibili. ACG non ha
collaudato tali prodotti e non può confermarne l’accuratezza delle prestazioni, la compatibilità con i
prodotti ACG o qualunque altra caratteristica. Qualunque richiesta sulle caratteristiche operative dei
prodotti non ACG deve essere rivolta direttamente ai rispettivi fornitori.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 3 di 167
Fatti salvi i danni causati da dolo o colpa grave, ACG non assume nessuna responsabilità circa i
contenuti del presente documento. In particolare, tali contenuti non rappresentano una promessa o
garanzia relativa all’idoneità a determinati scopi dei prodotti ACG oppure alla non violazione, da
parte dei prodotti ACG stessi, di leggi di qualsivoglia natura.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 4 di 167
Indice
NOTE E TRADEMARKS ....................................................................... 3
TABELLA DEGLI AGGIORNAMENTI .............................................. 8
1.
INTRODUZIONE ............................................................................. 9
2.
COMPONENTE VIEW ................................................................. 11
2.1 INTRODUZIONE ........................................................................................................................ 11
2.2 CARATTERISTICHE DI BASE...................................................................................................... 12
2.3 DIZIONARIO ............................................................................................................................. 17
2.4 COMPORTAMENTI GENERALIZZATI .......................................................................................... 19
2.4.1 Response dal server ...................................................................................................... 22
2.4.2 Funzioni di Base............................................................................................................ 23
2.4.3 Contesto e pre/postActions............................................................................................ 25
2.4.4 Accessibilità .................................................................................................................. 26
2.4.5 Messaggi ....................................................................................................................... 27
2.4.6 Menu contestuale .......................................................................................................... 27
2.5 COMPONENTI ........................................................................................................................... 29
2.5.1 Window.......................................................................................................................... 30
2.5.2 Panel ............................................................................................................................. 33
2.5.3 Field .............................................................................................................................. 38
2.5.4 XAction .......................................................................................................................... 44
2.5.5 Liste ............................................................................................................................... 48
2.5.5.1
Referenced Objects ............................................................................................... 53
2.5.5.2
Navigazione .......................................................................................................... 56
2.5.5.3
Liste con selezione multipla .................................................................................. 60
2.5.5.4
Rielaborazione Liste ............................................................................................. 62
2.5.6 Componente HeaderRows ............................................................................................. 68
2.5.6.1
Definizione di un oggetto HeaderRows ................................................................ 68
2.5.6.2
Gestione di una lista HeaderRows lato Controller ................................................ 68
2.5.6.3
Response xml ........................................................................................................ 68
2.5.6.4
Caricamento iniziale delle righe della lista HeaderRows ..................................... 69
2.5.6.5
Formattazione della stringa dati da inviare alla lista............................................. 69
2.5.6.6
Inserimento o modifica di una riga della lista ....................................................... 72
2.5.6.7
Cancellazione di una riga ...................................................................................... 73
2.5.6.8
Gestione del pannello piede .................................................................................. 74
2.5.6.9
Gestione di più liste nella stessa response ............................................................ 75
2.5.6.10
Label dinamiche .................................................................................................... 76
2.5.6.11
Modifica del menu di una riga .............................................................................. 76
2.5.6.12
Aggiunta di una riga in posizione successiva alla riga corrente ........................... 76
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 5 di 167
2.5.6.13
Creazione di una finestra tramite menu contestuale ............................................. 76
2.5.7 Lista Editabile ............................................................................................................... 78
2.5.7.1
Dblclick ................................................................................................................. 78
2.5.7.2
Onedit .................................................................................................................... 78
2.5.7.3
Xsend .................................................................................................................... 79
2.5.7.4
Riga in errore ........................................................................................................ 79
2.5.7.5
Riga in editazione.................................................................................................. 79
2.5.7.6
Combo dinamica su lista editabile ........................................................................ 80
2.5.8 Drilldown ...................................................................................................................... 83
2.5.9 Componente Tree View ................................................................................................. 85
2.6 SKIN E FONT ............................................................................................................................ 89
2.7 FAQ ........................................................................................................................................ 95
2.8 TOOL DI NAVIGAZIONE .......................................................................................................... 105
3.
COMPONENTE CONTROLLER .............................................. 111
3.1 INTRODUZIONE ...................................................................................................................... 111
3.2 INTEGRAZIONE VELOCITY – STRUTS IN ACG SERVICE BUS .................................................. 111
3.2.1 Benefici........................................................................................................................ 112
3.3 ACTION E FORM BEAN IN ACG SERVICE BUS ....................................................................... 115
3.3.1 ACGDynaActionForm ................................................................................................. 115
3.3.2 ACGDispatchAction .................................................................................................... 116
3.3.3 Global forwards .......................................................................................................... 118
3.3.4 Alcuni metodi di ACGDispatchAction ........................................................................ 118
3.4 CHAIN OF RESPONSIBILITY .................................................................................................... 119
3.5 CONFIGURAZIONE IN MODULI ................................................................................................ 119
3.6 ACGVALIDATOR .................................................................................................................. 120
3.7 MESSAGGI APPLICATIVI ......................................................................................................... 121
3.7.1 La classe BaseException ............................................................................................. 121
3.7.2 Catalogo messaggi ...................................................................................................... 121
3.7.3 Gestione dei messaggi in struts................................................................................... 122
4.
COMPONENTE MODEL ........................................................... 123
4.1 INTRODUZIONE ...................................................................................................................... 123
4.2 UTILIZZO DELLA FRAMEWORK HIBERNATE IN ACG SERVICE BUS ........................................ 124
4.2.1 Session Factory e Configurazione .............................................................................. 125
4.3 LEGACY CONNECTOR ............................................................................................................ 127
4.3.1 Diagramma architetturale .......................................................................................... 128
4.4 STRUTTURA DELLE TABELLE TEMPORANEE E DI LOG DELL’ELABORAZIONE .......................... 132
4.5 AMMINISTRAZIONE DELLE TABELLE TEMPORANEE ................................................................ 133
4.6 GENERAZIONE CODICE JAVA PER LA LEGACY PROGRAM INTERFACE ..................................... 134
4.6.1 Lancio del code generator .......................................................................................... 136
4.7 ACCESSO TRAMITE SERVIZIO WEB ......................................................................................... 139
4.8 REENGINEERING DEI PROGRAMMI LEGACY ............................................................................ 140
4.9 TABLE MANAGER .................................................................................................................. 143
4.9.1 Utilizzo tramite file di properties................................................................................ 143
4.9.2 Utilizzo file di properties a runtime ............................................................................ 147
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 6 di 167
5.
LINEE GUIDA PER SVILUPPO FUNZIONALITÀ VISION4149
5.1
5.2
ESECUZIONE OPERAZIONI IN BATCH ..................................................................................... 149
MODALITÀ DI RICHIESTA ESECUZIONE REPORT DI IBM COGNOS TRAMITE ACG SERVICE BUS
161
5.3 PERSONALIZZAZIONI IN ARCHITETTURA ACG VISION4 ......................................................... 164
5.3.1 Personalizzazione dello startup della web-application .............................................. 164
5.3.2 Personalizzazione della User Interface – posizionamento dizionari .......................... 165
5.3.3 Personalizzazione del richiamo dei report Cognos .................................................... 166
5.3.4 Gestione tabelle utente nei file ANTA200F, ASTA300F, ANTB300F, ASTB300F ..... 167
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 7 di 167
Tabella degli aggiornamenti
Data
PTF id
21/06/2011
SVB140031D
13/07/2011
SVB140034D
16/01/2014
SVB140108D
Descrizione
Aggiunto il paragrafo "2.6 Skin e Font" che descrive la
modalità di personalizzazione dell’aspetto grafico
dell’applicazione ACG Vision4
Aggiunti i paragrafi 4.9 “TableManager” e 5.3.4 “Gestione
tabelle utente in ANTA200F, ASTA300F, ANTB300F e
ASTB300F
Modifiche al paragrafo 2.4.4 Accessibilità.
Aggiunto 2.5.5 Liste - Formato visualizzazione liste
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 8 di 167
1. Introduzione
ACG Service Bus implementa un modello di sviluppo basato sullo standard open dell’MVC, ovvero
del Model, View e Controller, in base al quale le applicazioni vengono scritte secondo un’architettura
multilivello in cui ogni livello è logicamente separato rispetto agli altri.
Per Model si intende la rappresentazione dei dati di business dell’applicazione e le regole con
cui tali dati vengono interrogati, modificati o gestiti.
Per View si intende la componente responsabile della visualizzazione dei dati della
componente Model: i dati del Model possono essere visualizzati utilizzando viste diverse.
Per Controller si intende la componente responsabile dell’interazione tra View e Model: essa
interpreta le richieste della View, che non sono altro che le richieste dell’utente dell’applicazione,
inducendo azioni corrispondenti nella parte Model, selezionando la nuova View da visualizzare o se
del caso aggiorna la View stessa da cui è partita la richiesta.
In particolare, in ACG Service Bus il paradigma Model-View-Controller è stato così implementato:



La parte di View, responsabile della presentazione dei dati verso l’utente, è realizzata
interamente secondo le tecnologie Ajax e viene sviluppata sfruttando la framework open
source Dojo. E' costituita dal motore di gestione delle form (ACG Form Handler) che si
occupa di gestire gli aspetti di rendering utilizzando DHTML (codice HTML dinamico) e di
interattività utilizzando Ajax per la comunicazione asincrona con il server web: la View è
costruita sulla base delle informazioni contenute nei dizionari visuali (Data Dictionary).
La parte di Controllo è stata realizzata estendendo la framework Struts integrata con l’OSS
Velocity.
La parte Model si può implementare sviluppando codice in java basato sulla framework
Hibernate per gestire l’accesso ai dati oppure riutilizzando programmi legacy Rpg
congiuntamente a codice di interfacciamento con Java (Java Object Wrappers).
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 9 di 167
La logica di interazione tra le componenti costituenti l’applicazione è la seguente:





dal desktop ACG Service Bus, nel quale si integrano le applicazioni ACG Vision4, viene
richiesta l’esecuzione di un’operazione (il cui risultato è la visualizzazione di una finestra con
i dati relativi)
il Form Handler ricava dai dizionari visuali la struttura della finestra video e richiama l’URL
ad essa associato (richiamo del metodo di una Action di Struts)
viene verificato dal componente di autorizzazione che l’utente sia abilitato all’esecuzione
dell’operazione: in caso negativo viene restituito XML di errore al Form Handler
viene eseguito il metodo della Action di Struts che richiama la Business Logic e ritorna XML
di risposta contenente i dati del Model da visualizzare ed eventuali errori
la componente UIEngine interpreta la risposta xml ed aggiorna di conseguenza la finestra
video
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 10 di 167
2. Componente view
2.1 Introduzione
La UI (UserInterface) dei prodotti ACG Vision4 si basa sull’uso di un dizionario come
repository per le sue componenti (finestre, pannelli, campi,…). Le interfacce sono costruite
dinamicamente sul browser da un runtime javascript (denominato uiengine) creato appositamente per
l’architettura ACG Vision4, in base alle informazioni presenti nel dizionario.
Le interazioni con la parte server dell’applicazione sono, di norma, richieste asincrone di tipo
AJAX, raccolte ed elaborate da classi Java che restituiscono un response con un formato xml.
Tale risposta viene costruita automaticamente per mezzo di un meccanismo trasparente (basato
sui tools VelocityStruts) che accede agli attributi della classe Action della piattaforma STRUTS e
all'eventuale lista dei messaggi generati, formattandoli secondo dei template (output.vm,
check.vm,…).
Essa viene rimandata al browser dove l’uiengine l’interpreta e aggiorna l’interfaccia.
Alcuni comportamenti sono/saranno resi disponibili nell’uiengine e potranno attivarsi in base alle
proprietà definite nel dizionario, in base al contesto operativo (inserimento,visualizzazione,…), al
contesto applicativo.
L’uiengine fa uso della piattaforma open-source DOJO per la comunicazione fra browser e per
la creazione di alcuni componenti di base (FloatingPane, Accordion,…) o loro estensioni.
La UI è inoltre personalizzabile da parte dell’utente finale nella sua impostazione grafica
generale (sfondi, icone, colori) scegliendo fra i temi (skin) disponibili e in altri aspetti legati
all’usabilità quali tipo e dimensione font, modalità di attivazione (mediante click o movimento
mouse,…)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 11 di 167
2.2 Caratteristiche di base
Pannelli di logon
Implementano il Single Sign-On (SSO), memorizzano le informazioni sull’ultimo utente
collegato, la lista dei suoi sistemi informativi e quello usato per ultimo.
Desktop
L’ambiente di lavoro è composto da diverse sezioni in cui vengono lanciate le nuove funzioni
ACG Vision4 caratterizzate da una nuova interfaccia grafica.
Il desktop stesso è definito nel dizionario
Menubar
Toolbar
Nel desktop sono presenti i seguenti componenti:
Menubar (componente ad-hoc ACG Vision4)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 12 di 167
Posizionato sulla sinistra contiene le voci di partenza di un menu a tendina. I sottomenu sono
elementi ad albero creati dinamicamente a partire da dati provenienti dal database ACG e/o dai file di
personalizzazione (vedi Personalizzazione)
Il menu a tendina esploso viene “memorizzato” e riproposto al successivo posizionamento del
mouse sull’area della menu bar . Possibilità nelle voci di menu di segni di spunta per attivare o meno
un comportamento.
E’ basato sulle voci contenute nel dizionario di tipo NAV_ e parte da un nodo radice del tipo
diz['NAV_TOP']='ACG|USR|LAST|TOOLS|HELP';
che rappresenta i nodi di base del menu a tendina. La struttura ad albero si sviluppa definendo
per ogni nodo (che rappresenta un menu) i sottonodi che possono essere ancora nodi o azioni. Per
quest’ultime bisogna definire l’etichetta a video (label) e il comando da eseguire.
L’albero delle azioni di ACG Vision4 è quindi la composizione delle voci del dizionario di
tipo NAV_ , provenienti da

dizmenu.js

dall’esecuzione di appmenu.jsp (per le voci delle ACG WebEdition)

infine, se presenti, nella cartella <root>/customized/
dai file (opzionali)
menu_<utente>_<sistemainformativo>.js
ext_<utente>
che permettono di integrare/sovrascrivere le voci caricate dai file precedenti.
Esempio
Sotto il nodo TOOLS di NAV_TOP è presente il sottonodo SETTINGS con le sue label in lingua
diz['NAV_TOOLS']='..|SETTINGS|…';
diz['LBL_IT_SETTINGS']="Impostazioni";
diz['LBL_EN_SETTINGS']="Settings";
diz['NAV_SETTINGS']=' VIEWINFO |…|…|';
Il nodo “VIEWINFO” è un’azione che se invocata esegue in comando javascript
diz['LBL_IT_VIEWINFO']="Visualizza info";
diz['LBL_EN_VIEWINFO]="View info";
diz["CMD_VIEWCOOKIE"]="js:<comando visualizza info>;"
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 13 di 167
se l’azione lancia una gestione ACG Vision4:
diz["CMD_4RdP"]="js:xcrtWIN('F0','WIN_RdP');"
Richiamo di applicazioni/siti esterni in finestra ACG Vision4
Possibilità di aprire url di applicazioni o siti web in finestra separata o in finestra ACG Vision4; ciò è possibile indicando
come azioni nel menu
URL:<url>
Se si desidera in finestra esterna,
WIN:<url>
Se si vuole aprire l’url in una finestra del desktop.
In questo modo è possibile “integrare” a livello grafico le gestioni non ACG Vision4nel desktop (create con jsp, jsf,…)
Un limite è nella compatibilità delle gestioni integrate, queste devono consentire il lancio in sottofinestra del browser e
non eseguire operazioni sul documento al livello superiore.
Esempio:
diz['LBL_IT_4EXTLINK']="Collegamento esterno ACGINFO in finestra separata";
diz['LBL_EN_4EXTLINK']="External link (separate window)";
diz["CMD_4EXTLINK"]="URL:http://www.acginfo.it"
diz['LBL_IT_4EXTLINKV4']="Collegamento esterno ACGINFO in finestra ACG VISION4";
diz['LBL_EN_4EXTLINKV4']="Link to ACGINFO in a ACG VISION4window";
diz["CMD_4EXTLINKV4"]="WIN:http://www.acginfo.it"
Toolbar (componente ad-hoc ACG Service Bus)
Contenente una serie di bottoni funzionali, completamente personalizzabile (vedi Personalizzazione)
Esempio: desktop ACG Vision4con 2 topbar
diz["TOPBAR0"] = '{"actions":[ "ACT_REFRESHDESKTOP","ACT_NEWDESKTOP" ] }';
diz["TOPBAR1"] = '{
"actions":["ACT_CLIENTSETTINGS","ACT_DUPFRM","ACT_EXCEL","ACT_WORD","ACT_MAI
L" ] }';
diz["LBL_EN_DESKTOP"]="ACG Vision4";
diz["LBL_IT_DESKTOP"]="ACG Vision4";
diz["DESKTOP"]='{ "label":"DESKTOP" ' +','+
' "toolbars":[
'+
$d("TOPBAR0") + ','+
$d("TOPBAR1") + ‘ ] } ';
Toolbar
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 14 di 167
Window funzioni ACG Service Bus
Window
Taskbar
Sono finestre che attivano funzioni applicative sviluppate usando l’architettura ACG Vision4.
Sono indipendenti e possono essere lanciate in maniera multipla anche sulla stessa funzione;
hanno le consuete caratteristiche di minimizzazione, massimizzazione, ridimensionamento;
prevedono un controllo alla chiusura in presenza di modifiche non salvate.
Sono composte da:
a. Finestra (estensione del FloatingPane di DOJO)
b. Pannelli (dictionary-based)
c. Pannello Tabbed (dictionary-based)
d. Pannello Lista (pf-based)
e. Componente TestataRighe (componente ad-hoc ACG Service Bus)
f. ReferencedObject, ovvero funzione ? di ACG (dictionary/pf-based)
g. Calendario (estensione del componente DOJO con festivi configurabili)
h. Componente note
TaskBar
Posizionata nella parte inferiore, realizzato come estensione del componente DOJO
(ACGTaskBar) elenca le finestre attive, con titolo troncato (visibile nella forma completa
posizionando il mouse) e completo di una icona
che consente di lanciare la chiusura di tutte le
finestre ACGv4 presenti nella TaskBar.
Altre funzionalità disponibili nel desktop
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 15 di 167
Nel menù Strumenti sono a disposizione una serie di funzionalità:
Funzionalità di log
A partire dal menù ad albero Strumenti -> Debug -> Raccolta informazioni -> Stampa Log è
attivabile la funzione di log sul client, avente le seguenti caratteristiche:





Il Log viene visualizzato in una finestra separata
Molto spazio a disposizione
Possibilità di ricerca con diverse modalità
Possibilità di abilitare o meno l’emissione dei messaggi
Barra per filtrare i messaggi in base alla categoria
o Error (messaggi tipo ERR…)
o Warn (messaggi tipo WARN…)
o Info (altri messaggi, esempio <response>…)
o Debug (tipo non definito)
A partire dal menù suddetto è possibile anche Cancellare il Log ed Eliminare il Limite del Log
disabilitando così il limite massimo al log.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 16 di 167
Cambio di Sistema informativo
E’ possibile a partire dal Menu Preferiti lanciare la funzione di Cambio di Sistema Informativo che
permette all’utente di passare a un Sistema Informativo diverso da quello corrente (scelto fra quelli a
lui disponibili).
Viene richiesta conferma dell’operazione e tutte le finestre sono chiuse.
Controllo Dizionari e Controllo Componenti
I controlli sono attivabili da Strumenti -> Debug -> Controlli.
2.3 Dizionario
Tutte le componenti della UserInterface delle nuove funzioni ACG Vision4 (finestre, pannelli,
campi,…) sono definite come voci di un dizionario.
Esempio:
dizionario[campoCodiceCliente]=stringa delle caratteristiche del campo
Il dizionario è destinato a contenere anche altre informazioni, pertanto è stata adottata la
seguente convenzione:
- ogni voce del dizionario è preceduta da un prefisso ( in genere di 4 caratteri ) che consente di
identificare la categoria di appartenenza. Esempio:
diz["LBL_DATE"]='Data';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 17 di 167
I prefissi definiti sono:
LBL_
Etichetta
generica
o
risorsa
stringa
WIN_
Finestra
PNL_
Pannello
FLD_
Campo
ACT_
Funzione (bottone e simili)
CMD_ACT_
Comando della funzione
CMD_
Comando
URL_
Indirizzo da invocare
URL_PARMS_
Parametri dell’indirizzo
VAL_
Lista valori tipo Enum
REF_
Riferimento ad altra voce diz
Il concetto di dizionario permette di riutilizzare ove previsto le informazioni comuni a più
definizioni; ad esempio una stringa come etichetta o uno stile predefinito o un campo comune a più
pannelli. I dati del dizionario sono disponibili come tabella di database (generalmente DICT400F) e a
partire da questo saranno generati uno o più file di dizionario in modo da gestire in modo efficiente il
trasferimento sul client.
I file di dizionario sono raggruppabili nelle seguenti categorie:

di base (contengono le voci base della Vision4)
diz.js
contiene l’inizializzazione e le voci di applicazione
dizmenu.js
contiene le voci del menu di base
diz<country>.js
contiene le label e i messaggi in lingua

di prodotto (contengono le voci relative ad un prodotto)
diz_<acronimo_prodotto>.js
contiene le voci relative a risorse riferite dal prodotto
diz_<acronimo_prodotto>_<country>.js
contiene le label e i messaggi in lingua delle voci
relative a risorse riferite dal prodotto

dipendenti dal sistema informativo (situati in una cartella /addon/diz/<sistema informativo>,
permettono di integrare o sovrascrivere le voci degli altri dizionari e devono mantenere la
notazione di quelli di prodotto.
A runtime verranno caricati i dizionari nella lingua corrente, i dizionari di base e tutti quelli che
rispettano la notazione dei dizionari di prodotto nella cartella:
<root>/addon/diz/
ed eventualmente quelli presenti nella cartella:
<root>/addon/diz/<sistema informativo>/
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 18 di 167
Le etichette saranno definite nel seguente modo
-
nel file dizIT.js diz["LBL_IT_SAVE"]='Salva’;
-
nel file dizEN.js diz["LBL_EN_SAVE"]='Save’;
Sono previsti alcuni meccanismi per minimizzare le informazioni richieste per definire gli oggetti,
alcune sono dedotte o recuperate per mezzo delle convenzioni.
Esempio: Id di un oggetto
Tale informazione è generalmente opzionale; viene costruito a partire dalle informazioni disponibili.
Di seguito le assunzioni per tipologia di oggetto:

XWIN: l’id sarà creato partendo dalla chiave e con un prefisso che ne garantisca l’univocità.

XFIELD: l’id è opzionale, se non definito verrà adottato come id l’informazione attrname che
rimane obbligatoria.

XPANEL: L’id può essere un id di fantasia o lo si omette se l’inclusione dei pannelli avviene
attraverso le funzioni $d o $d2.
Esempio
diz["PNL_SampleList"]='{ "id":"myId", "label":"LIST", …}
diz["PNL_Sample3List"]='{ "label":"LIST", "init":"true", '…}
diz["PNL_Sample3ContainingPanel"]='{ "id":"Sample3ContainingPanel",
"style":"position:relative;width:100%;height:100%;" '
+','
+' "formId":"Form1", '
+' "collapsed":"false", label:"Pannello in pannello", '
+' "panels":[ '
+$d("PNL_SampleList")
+' , '
+$d2("PNL_Sample3List", " id:'Pannello2', … ")
+' ] '
+' } ';
Sono comunque ancora supportate le definizioni preesistenti del tipo:
diz["PNL_RdPList"]='{ id:"RdPList", "label":"LIST", "init":"true", '
diz["WIN_RdPList"]= '{"window":{ "id":"RdPWindowList", "width":700, "height":300, '
+ ' "panels":[ '
+ diz["PNL_RdPList"]
+' ] } }';
 XLABEL: per l’attributo label, se è definito un valore questo viene considerato come chiave
per la ricerca nel dizionario; se la voce non è presente viene restituita la chiave stessa.
2.4 Comportamenti generalizzati
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 19 di 167
Ecco la sintesi dei principali comportamenti attivabili per mezzo delle proprietà degli oggetti nel
dizionario.
Finestra
- struttura (pannelli, tabbed) e posizionamento
- gestione messaggi con reindirizzamento al campo in errore
- init sulla finestra usata per impostare i dati passati all’atto della creazione
Pannelli
- tipologia (form, tabbed, lista,…)
- struttura (normale o griglia)
- barra azioni (opzionale)
- gestione comunicazione ajax
- url associato
- reload
- passaggio parametri
- abilitazione/disabilitazione e occultamento dell’intero pannello mediante operazioni invocate
nella response dal server come pre/postActions.
- azione di init (inizializzazione) a livello di pannello normale,
proprietà formId) o tabbed (senza specificare formId)
multipanel (impostando la
- disabilitazione dei campi e tasti all’invocazione di una azione sul server o “offuscamento”
dell’intero pannello in attesa dell’inizializzazione dello stesso
- validazione del form prima dell’invocazione di una operazione sul pannello (Es. controllo sul
browser dei campi obbligatori sull’invocazione della save)
- funzione standard associabile all’enter
- shortcut (vedi Accessibilità)
- controllo alla chiusura di eventuali modifiche in sospeso
- menu contestuale (sui pannelli di tipo lista)
Campi
- label (sopra o a sinistra)
- help di campo
- icona di campo per attesa, errore,…
- campo descrizione associato
- funzione controllo all’exit focus con eventuali campi associati
- controllo tastiera per campi numerici e data
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 20 di 167
- controllo tastiera in base a set caratteri ammessi
- formattazione migliaia campi numerici
- obbligatorietà, stile e controllo
- readonly
- disabilitazione in base al contesto (immissione, modifica,…)
- uppercase
- componente ReferencedObject che realizza la funzione ? di ACG sul campo
- visualizzazione messaggio di errore (flying message) e/o visualizzazione dello stato di errore sui
campi multipli mediante bordo rosso.
- richiamo funzioni exitfocus solo se il valore è modificato o mediante forzatura, per evitare
l’invocazione al server anche quando il valore non è cambiato.
- menu contestuale
- possibilità di associare un campo “Note”
Help
E’ possibile associare un testo di aiuto




sul campo
sull’azione (bottone)
sul pannello
sulla window
Le modalità di visualizzazione previste sono:


flying text (il testo appare quando il mouse si posiziona sull’elemento)
window separata (F1 sull’elemento evidenziato)
La prima modalità è adatta se il testo ha una lunghezza limitata (<100 char), può essere definito
come voce di help direttamente nel dizionario.
Esempio
diz["FLD_Sample7"]='{ "id":"Sample7", "attrname":"CDCSO", …
"help":"true"…
sarà recuperata la voce
diz["HLP_IT_Sample7"]='con help=true, si recupera una voce da dizionario per mezzo dell\' id (Sample7)';
oppure specificando l’attributo
diz["FLD_Sample7"]=={… "help":"Sample7Bis" …}
sarà recuperata la voce
diz["HLP_IT_Sample7Bis"]='con help=Sample7Bis, si recupera la voce indicata dal dizionario';
Per contenuti più corposi ed articolati (immagini) è necessario usare la modalità finestra separata.
Nel dizionario la voce di help conterrà l’url della risorsa che contiene l’help che sarà visualizzato in
una sezione apposita del desktop o in finestra separata.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 21 di 167
La finestra separata è unica per tutti i pannelli di help.
Nella window ACG Vision4è stato aggiunto un tasto
che permette di evidenziare nel pannello gli
elementi che hanno un file di help associato mediante l’icona , accessibile da mouse e da tab.
Esempio
diz["HLP_SampleCombo1onPanel7Help"]='/products/E01/help/IT/FunzioneHelp.html';
2.4.1
Response dal server
La risposta proveniente dal server è, per funzioni ACG Service Bus, in formato xml con il
seguente schema:
<response con le informazioni sulla richiesta, sulla finestra, pannello e
capo origine della richiesta e contesto operazione>
<preActions>…</preActions>
<postActions>…</postActions>
<data è il buffer dati>
<item
name="nomeparametro"
value="valoreparametro"
[display=”true”|”false”]
[visibility=”true”|”false”]
[disabled="true"|”false”]
>
</item>
<action name=”nomeazione"
[display=”true”|”false”]
[visibility =”true”|”false”]
[disabled="true"|”false”]
>
</action>
</data>
<msgs>
<msg tgt="nomeparametro"> testo messaggio </msg>
</msgs>
</response>
dove nomeparametro coincide con attrname definito per l’oggetto XFIELD.
La response a seguito di un CHECK che ritorni una descrizione e nessun errore è del tipo:
<?xml version="1.0" ?>
<response xwin="3_F1_WIN_RdP" xform="3_F1_WIN_RdP_PanelInPanel_Form1"
xfield="3_F1_WIN_RdP_PanelInPanel_Form1_CDCSO" xmethod="checkCustomer"
xexec="" xcontext="2" >
<preActions></preActions>
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 22 di 167
<postActions></postActions>
<data>
<item name="CDCSO_rascl" value="BENDER PLASTICA
</data>
srl"></item>
<msgs>
</msgs>
</response>
La response a seguito di un SAVE che ritorni dei dati e dei messaggi di errore è del tipo:
<?xml version="1.0" ?>
<response
xwin="1_F3_WIN_DynaAddressCHECK"
xform="1_F3_WIN_DynaAddressCHECK_DynaAddressPanel_Form1"
xmethod="SAVE" xcontext="0">
<data>
<item name="name_descr" value="BENDER Plastica"></item>
<item name="exec" value=""></item>
<item name="address" value="23qer"></item>
<item name="email" value="erwrewq"></item>
<item name="name" value="000100"></item>
</data>
<msgs>
<msg>Dati non validi</msg>
<msg tgt="address">Indicare Via, Corso, Piazza, Vico..., Lungo...,
Strada..., in questo campo</msg>
<msg tgt="email">Formato email errato</msg>
<msg tgt="name">Codice cliente gia' presente</msg>
</msgs>
</response>
E’ possibile produrre una response contenente item non strettamente collegati al form/pannello
di partenza della richiesta. L’engine avvalorerà gli item trovati nell’ambito del form indicato, in caso
di insuccesso li ricercherà all’interno di tutti i pannelli della XWIN. Analogo comportamento è
previsto per le actions o operazioni sottostanti ai BUTTON.
Le azioni nella response hanno id del tipo ACT_xxx_yyy ovvero sono referenziabili per mezzo
della loro chiave nel dizionario.
Esempio:
<action name="ACT_Banca_saveCont" disabled="true"
></action>
2.4.2 Funzioni di Base
Sono disponibili le seguenti funzioni di base sui pannelli:

xreload

xclose
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 23 di 167

xcollapse/xexpand/xtoggle

xcheck(url, [force])

xvisibility,xdisplay,xreadonly
Esse possono essere invocate:
 direttamente sul browser
Esempio: ad un bottone, la XACTION relativa invocherà l’aggiornamento di un pannello.
 come risultato di una richiesta al server
Esempio: nella response proveniente dal server, nel parametro xexec è presente l’invocazione
dell’aggiornamento di un pannello
Vediamo con maggior dettaglio alcune di queste funzioni:
xcheck(url [,force])
Permette di eseguire una richiesta ajax su un campo, specificando url. Nella richiesta sarà incluso il
valore del campo e gli eventuali parametri aggiuntivi (altri campi dei pannelli).
La richiesta non viene rilanciata (ad esempio se attivata sull’exit focus) se il valore rimane lo stesso,
altrimenti impostare il flag opzionale [force]
diz["URL_CustomerServlet"]='../DynaAddress.do';
diz["FLD_CustomerIdKey"]='{ "attrname":"name", …,
"onblur":"xcheck('+"'"+'URL_CustomerServlet'+"'"+')"
diz["FLD_CustomerIdKey"]='{ "attrname":"name", …,
"onblur":"xcheck('+"'"+'URL_CustomerServlet'+"'", true+')"
xreadonly, xvisibility, xdisplay, xreload
E’ possibile invocare le suddette API passando come identificativo
 il nome del pannello (attributo id)
 l’identificativo assoluto del pannello (id composto da <id finestra corrente>…<id pannello>)
In questo modo è possibile pilotare il ricaricamento, la visualizzazione o la disabilitazione di un
pannello di una qualsiasi window ACGv4 presente nel desktop conoscendone l’id assoluto.
Esempio:
Supponiamo di avere una window A che apra una window B; il comando di apertura della window B
giunge al server corredato dei parametri xwin (identificativo assoluto della window A) e xform
(identificativo assoluto del pannello da cui è partita la richiesta). Queste informazioni possono
successivamente essere utilizzate dalla parte controller della finestra B per invocare un’azione sulla
finestra o su un pannello della finestra A (ad esempio la disabilitazione).
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 24 di 167
Riassumendo:
xreadonly([“panelId”|”absolutePanelId”],[”true”|”false”])
xvisibility([“panelId”|”absolutePanelId”],[”true”|”false”])
xdisplay([“panelId”|”absolutePanelId”],[”true”|”false”])
xreload([“panelId”|”absolutePanelId”])
Esempio:
<postActions>
<action name='xreadonly("1_F0_WIN_Sample_SamplePanel","false")' />
</postActions>
2.4.3 Contesto e pre/postActions
Il contesto definisce la tipologia di operazione in corso e permette, impostato opportunamente,
di attivare dei comportamenti in modo automatico. Ad esempio un campo che ha la proprietà
disableonchange=”true” sarà automaticamente disabilitato se il server imposta il contesto al valore 2
(“modifica”).
Il contesto può assumere i seguenti valori:
0
non definito
1
New
I campi/azioni con disableonnew sono disabilitati
2
Change
I campi/azioni con disableonchange sono disabilitati
5
View
Tutti i campi e azioni sono disabilitate
A volte si vuole far eseguire all’interfaccia delle operazioni dipendenti dal contesto applicativo
ma non mappabili negli stati predefiniti.
Ad esempio in una situazione specifica prima o dopo aver avvalorato il contenuto di un
pannello con una response è necessario disabilitare o rendere non visibile un altro pannello, ricaricare
un'altra sezione,...
Una o più operazioni di questo tipo possono essere inserite nella response in due sezioni
denominate <preActions> e <postActions> che saranno eseguite nella sequenza.
Utili per gestire in modo dinamico il comportamento dei vari pannelli (ad esempio se si vuole
rendere non visible o disabilitare l’intero contenuto di un pannello con dei comandi inseriti nella
response).
Esempio di response operante sulla visualizzazione dei campi
<preActions>
<action name='xdisplay("DynaAddressPanel","false")' />
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 25 di 167
<action name='alert(" ho nascosto il pannello")' />
</preActions>
<data>…</data>
<msg>…<msg>
<postActions>
<action name='xdisplay("DynaAddressPanel","true")' />
<action name='alert(" ho ripristinato il pannello")' />
<action name='xreadonly("DynaAddressPanel","true")' />
<action name='alert(" ho disabilitato il pannello")' />
<action name='xreadonly("DynaAddressPanel","false")' />
<action name='alert(" ho abilitato il pannello")' />
</postActions>
Esempio di comando complesso o metodo javascript nella postActions
E’ possibile emettere nella postAction l’esecuzione di un command complesso che nell’esempio fornito

Chiede la conferma all’utente

In caso affermativo reinvoca un’azione sul server
Nel dizionario:
diz["CMD_SampleConfirm"]
= "js:if(confirm('Sei sicuro?')){ xdirectsend('../DynaAddress.do?action=CONFIRMED_DELETE') }";
Nella response dovrà essere invocato cosi:
<postActions>
<action name="CMD_SampleConfirm"/>
</postActions>
2.4.4
Accessibilità
L’applicazione prevede l’accesso via mouse o tastiera. Per garantire l’usabilità via mouse, i tasti
funzionali sono dimensionati opportunamente (min 20x20).
Tutte gli elementi dell’interfaccia sono accessibili mediante tastiera (TAB). E’ possibile modificare
l’ordine agendo sul parametro tabIndex dei campi e dei tasti funzione.
Acceleratori
Sono previsti alcuni tasti acceleratori per le funzioni usate più frequentemente:

CTRL-S save (disponibile nei pannelli con azione SAVE standard*)

CTRL-X close window

CTRL-N o CTRL-n apertura note

CTRL-F apertura componente ricerca stringa, su liste PF (PersistentFilter)

CTRL-SPACE apertura componente lista RO (ReferencedObject)

ENTER/CTRL submit

F3 close window
* esempio: gestione Operazioni di SVB
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 26 di 167
E’ possibile personalizzare l’associazione per alcuni tasti (ad esempio il submit può essere associato
all’ENTER o al tasto CTRL).
2.4.5
Messaggi
L’interfaccia grafica prevede l’emissione di messaggi secondo diverse modalità, dipendenti
dall’importanza, dal contesto applicativo e grafico.
I messaggi di attesa di una risposta dal server a livello di finestra o di campo (nel caso di
richieste AJAX) evidenziate dall’icona animata
.
Le indicazioni di errore sui pannelli sono rappresentati

Tutti i campi in errore vedono il loro bordo modificato in rosso.

Sul primo dei campi in errore appare un flyingbox

Il testo di tutti i messaggi viene aggiunto nel combo box situato nel bordo inferiore della
finestra; il click sul singolo errore porterà il focus sul campo relativo
2.4.6 Menu contestuale
La funzione di menu contestuale è disponibile attualmente sugli oggetti XFIELD e XPANEL
di tipo lista. E’ opzionale e attivabile specificando la proprietà "menu" avente come valore la chiave
del dizionario che elenca i comandi disponibili.
Questo attributo può essere una chiave di tipo MNU_xxxx che elenca una serie di comandi (voci di
tipo CMD_xxx) o un nodo del menu ad albero (vedi campo Sample2TYPE, Esempio 2).
E’ previsto il passaggio di parametri:
 nel caso della lista la chiave della riga evidenziata, anche di tipo composta, le cui parti
sostituiranno le occorrenze di !key
 nel caso di un campo il suo valore
Esempio: menu contestuale sulla lista
diz["MNU_SampleList"]=' [ "CMD_NEWRDP","CMD_MODRDP","URL_URLEsterno" ] ';
diz["PNL_SampleList"]='{ "id":"RdPList", "label":"LIST", "init":"true", '
+' "style":"height:100%;width:100%;" '
+' , '
+' "url":"URL_RdPList" '
+' , '
+' "menu":"MNU_SampleList" '
+' , '
+' "dblclick":"ACT_DblClickRdPList" '
+' } ';
Esempio: sul campo Customer è attivato un menu contestuale con 3 azioni
diz["CMD_NEWRDP"]="js:xcrtWIN(\'F1\',\'WIN_RdP\')";
diz["CMD_MODRDP"]="js:xcrtWIN(\'F1\',\'WIN_RdP\', \'[!key]\' )";
diz["URL_URLEsterno"]='http://www.ibm.com?id=!key&id2=!key';
diz["MNU_SampleList"]=' [ "CMD_NEWRDP","CMD_MODRDP","URL_URLEsterno" ] ';
diz["FLD_Customer"]='{"attrname":"cdcli","menu":"MNU_SampleList", …} ';
oppure
diz["FLD_CustomerIdKey"]='{"attrname":"name","menu":"MNU_SampleList", …} ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 27 di 167
Esempio: invocare Actions sul server da menu contestuale
diz["LBL_IT_CMD_SampleServlet"]='Invocazione diretta action';
diz["CMD_SampleServlet"]="xsend('../MyAction.do?tipoazione=CANCELLA')";
diz["MNU_SampleList"]=' ["CMD_SampleServlet",…] ';
diz["PNL_SampleList"]='{…, menu":"MNU_SampleList" ' }’
Passaggio parametri al menu contestuale delle liste
E’ possibile passare oltre alla chiave del record selezionato (notazione !key) anche valori provenienti da campi presenti in
altri pannelli specificando una voce del dizionario del tipo URL_PARMS_xxx.
Questa voce conterrà l’id dei campi da passare (pannello_[form]_attrname) sulla falsa riga delle actions definibili sul
pannello.
diz["URL_PARMS_SampleServlet2"]=' [ "Sample2ContainingPanel_Form1_S2TYP" ] ';
diz["LBL_IT_CMD_SampleServlet2"]='Invocazione diretta + passaggio valore campo di altro pannello';
diz["CMD_SampleServlet2"]="xsend('../DynaAddress.do?selectedKey=!key')";
diz["MNU_SampleList"]='…,"CMD_SampleServlet2"] ';
diz["PNL_SampleList"]='{ ... “menu":"MNU_SampleList"
© Copyright ACG Srl 2014 Tutti i diritti riservati.
...}’
Pagina 28 di 167
2.5 Componenti
Di seguito le schede tecniche per i componenti disponibili.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 29 di 167
2.5.1 Window
XWIN
Oggetto: window
Sintassi: diz[“WIN_nomewindow”]
Attributo
Sintassi
Opzionale/
Obbligatorio
id
Opzionale
width
Opzionale
height
Opzionale
panels
[ <definizione pannello> , …]
Obbligatorio
parms
[ ‘fieldId’,…]
Opzionale
type
Nome del FloatingPane personalizzato
Opzionale
url
init

permette di invocare un’azione sul server alla chiusura della
finestra

usato per invocare l’inizializzazione personalizzata
[“init”:“true”|”false”]
Opzionale
Opzionale
indica se l’inizializzazione di window è attiva
resizable
[“resizable”:“true”|”false”]
Opzionale
Se non specificato si assume che sia True. Se false si assume
che

Sia una finestra il cui contenuto sia di dimensioni limitate
e non variabili

Vengono rimosse le azioni di minimizzazione,
massimizzazione,..

Viene centrata nello schermo
Inizializzazione della window
La funzione di creazione della window prevede la possibilità (opzionale) di inizializzazione.
Questa viene attivata impostando la proprietà "init":"true" a livello di window.
L’url usato per l’inizializzazione è l’url definito a livello di window.
diz["WIN_Sample9"]= '{"window":{ "id":"Sample9", … , "init":"true",'… "url":"../DynaAddress.do"'…
Questa inizializzazione è eseguita prima di quella dei pannelli (se presente "init":"true" sui singoli pannelli).
In generale, se presente, l’inizializzazione sulla window dovrebbe essere in alternativa a quella dei singoli pannelli, a
meno di particolari esigenze applicative.
La nuova funzione di creazione della window è
function xcrtWIN(aPref,aWinId[,aParmsValues,aInitParms]){
e consente di creare la window passando un metodo di init personalizzato (che sovrascriverà quello standard)
diz["CMD_4Sample9"]="js:xcrtWIN('F0','WIN_Sample9','[]','xmethod=mioinit');"
e la richiesta sarà del tipo:
../DynaAddress.do?xwin=1_F0_WIN_Sample9&xmethod=mioinit
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 30 di 167
E’ possibile anche passare altri parametri provenienti da una lista
xcrtWIN('F0','WIN_Sample9','[!key]','xmethod=mioinit&mioparm=EDIT');"
in questo caso è necessario impostare a livello di window la definizione del campo passato
diz["WIN_Sample9"]= '{"window":{ "id":"Sample9", …
+', "parms": [ "Sample9_Form1_CDCSO" ] '
in modo da ottenere una invocazione di questo tipo:
../DynaAddress.do?xwin=1_F0_WIN_Sample9&CDCSO=5&xmethod=mioinit
E’ possibile anche passare altri parametri statici
diz["CMD_4Sample9"]="js:xcrtWIN('F0','WIN_Sample9','[]','xmethod=mioinit&mioparm=EDIT');"
in questo caso avrò
../DynaAddress.do?xwin=1_F0_WIN_Sample9&CDCSO=5&xmethod=mioinit&mioparm=EDIT
Passaggio di parametri alla window
In questo esempio la window conta 2 pannelli e riceve un parametro passato in fase di creazione che andrà ad avvalorare
un campo (RdPPanel_Form1_num).
diz["WIN_RdP"]= '{"window":{ id:"RdPWindow", "width":700, "height":500, '
+ ' "panels":[ '
+diz["PNL_RdPPanel"]
+','
+diz["PNL_RdPRowsList"]
+' ] '
+' }
,'+
' "parms": [ "RdPPanel_Form1_num" ] '
+' }';
Uso di window personalizzate
La proprietà “type” per le window consente l’uso di FloatingPane personalizzati nel desktop ACG Vision4. Prerequisito la
presenza degli oggetti necessari:
MyFloatingPane.html
MyFloatingPane.css
MyFloatingPane.js
nelle cartelle di dojo e l’inserimento del file
MyFloatingPane.js
fra i require in /addon/b_dsk.jsp
Esempio
diz["WIN_RO"]= '{ "type":"ACGROFloatingPane", "window":{ "id":"ROWindow",
Chiusura forzata di una window
In caso di errore è possibile chiudere una window emettendo un messaggio.
Il metodo da impostare nelle postAction è del tipo
xclose(winId, msg)
con la winId che ha lo stesso valore della xwin e per testo un testo già localizzato;
L’utente riceve l’errore nella popup, clicca su OK e la finestra si chiude invocando il metodo close sul server (se l’url della
window è impostato)
Parametro InitialState
parametro initialState nella definizione della window.
Viene ignorato se sono presenti i parametri width e height.
Riassumendo:
diz[WIN_<id> "]= '{"window":{ "id":"<id>", "initialState":"[maximized|minimized]",…
Esempio:
diz["WIN_Sample"]= '{"window":{ "id":"Sample", "initialState":" maximized ",…
oppure
diz["WIN_Sample"]= '{"window":{ "id":"Sample", "width":100, "height":200,…
Proprietà Title
E’ possibile passare il titolo della window nel comnado di creazione
function xcrtWIN(aPref,aWinId,aParms,aInit,aType,aTitle)
Il parametro aTitle può essere il valore definitivo o nel dizionario diz_<acron.prod.>_<locale>.js
Es.
diz['LBL_IT_XAAC0']="Lista Clienti";
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 31 di 167
diz['LBL_EN_XAAC0']="Customer List";
diz["CMD_4PFList"]="js:xcrtWIN('F0','WIN_PFList','[com/ibm/acg/xml/AAC0.xml]',undefined,undefined,'XAAC0');"
oppure
diz["CMD_4PFList"]="js:xcrtWIN('F0','WIN_PFList','[com/ibm/acg/xml/AAC0.xml]',undefined,undefined,'miotitolo');"
Troncato al valore della variabile globale $$maxtit (impostato a 40)
Meccanismo recupero del title:
//
first, check if passed as parameter,
//
then retrieve from property title in win definition
//
otherwise get it from labels using winId
Azione per collassare/espandere tutte i pannelli
E’ possibile collassare e riespandere tutte le sezioni definite collassabili (impostazione di un valore nella property
collapse del pannello). Al primo click tutti pannelli sono collassati, al secondo sono ampliati.
La modifica non è persistente, alla riapertura del pannello saranno riprese le impostazioni di default dei singoli pannelli.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 32 di 167
2.5.2 Panel
XPANEL
Oggetto: pannello
Sintassi: diz[“PNL_nomepannello”]
Attributo
Sintassi/Note
Opzionale/
Obbligatorio
id
panels
label
Obbligatorio
[ <definizione pannello> , …]
Se esiste, realizza il bordo con etichetta
Opzionale
Opzionale
E’ possibile modificarla dinamicamente (vedi esemp.)
fields
[ <definizione campo> , …]
Obbligatorio
actions
[ <definizione tasto azione> , …]
Opzionale
enterAction
Permette di definire la action da lanciare sull’INVIO sul pannello.
All’ENTER dell’utente, invocherà il click sul button con id del tipo
<formId>_SAVE
Opzionale
L’INVIO può essere personalizzato (attivato su tasto ENTER o
CTRL)
Es. "enterAction":"SAVE"
rows
rows:#
Opzionale
insieme all’attributo cols attiva la definizione del pannello “tipo
griglia”
cols
cols:#
Opzionale
style
<definizione di stile>
Obbligatorio
bar
toolbar grafica per azioni standard (SAVE,NEW,…),
Opzionale
relativa al pannello,
posizionata in alto nel pannello, subito a destra della etichetta del
bordo (se presente),
sempre presente, contiene
l’icona di attesa risposta dal server
icone azioni standard
<definizione di barra per azioni non standard>
collapsed
type
se definito abilita la funzione di collapse/restore sul pannello



"tabbed"
"grid"
"list" per gestire fonti dati di tipo lista diverse
dall’applicazione PF
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Opzionale
Opzionale
Pagina 33 di 167

"headerRows" per identificare il componente testatarighe
linked
contiene l’id
o la serie di identificativi di altri componenti
collegati. Utilizzato nel componente testataRighe
Opzionale
menu
contiene la chiave del menu contestuale associato al pannello (di
tipo lista)
Opzionale
oncollapse
metodo eseguito all’occultamento del pannello
Opzionale
onexpand
metodo eseguito all’espansione del pannello.
Opzionale
creation
usato nei tabbed per rimandara la creazione de pannello al click
dell’utente sulla linguetta del tabbed
Opzionale
valori ammessi:deferred
Proprietà per “attivare” il pannello come form
formId
Obbligatorio
url
Obbligatorio
init
init=”true”
Opzionale
Se esiste, alla creazione della finestra viene invocato l’url del
pannello con il method init
Esempio di pannello di tipo grid, con inizializzazione, posizionamento campi nelle celle e 2 azioni nella
action bar:
diz["PNL_RdPPanel"]='{ id:"RdPPanel", "label":"RdPPanel", "init":"true", "url":"../DynaAddress.do",
"formId":"Form1", "rows":5, "cols":5,
"style":"position:relative;top:100;left:100;width:100%;height:100%;"'
+','+
' "fields":[ '+
$d2("FLD_RdPDATA", "row:0, col:0") …
+','+
$d2("FLD_RdPStato", "row:1, col:3, tabIndex:-1")
+
']'
+','+
' "bar":{row:2, col:1, span:2, "buttonstyle":"width:100;" } ' +','+
' "actions":[ '+
$d("ACT_DynaAddress_CANCEL")
+','+
$d("ACT_RdP_SAVE")
+
']'
+' } ';
Esempio di pannello con sovrascrittura delle proprietà (tabIndex e labelStyle) di un campo:
diz["PNL_RdPPanel"]='{ id:"RdPPanel", …
' "fields":[ '+
$d2("FLD_RdPStato", "row:1, col:3, tabIndex:-1, labelStyle:'top' ")
']'…
+' } ';
+
Esempio d’uso della proprietà “oncollapse/onexpand” per i pannelli
Se definite vengono eseguire all’espansione o all’occultamento del pannello.
Esempio:
Si desidera aggiornare la lista all’espansione della suo pannello originariamente chiuso.
diz["ACT_Sample5onexpand"]='{ "url":"xreload(\'Sample5List\')" } ';
diz["ACT_Sample5oncollapse"]='{ "url":"confirm(\'action on collapsing...\')" } ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 34 di 167
diz["WIN_Sample5"]= '{"window":{ "id":"Sample", '
+' "panels":[ '
+$d2("PNL_SampleList", ' "id":"Sample5List", "init":"false",
collapsed:"true", onexpand:"ACT_Sample5onexpand",
oncollapse:"ACT_Sample5oncollapse" ')
+' ] '
+' }'
+' , "parms": [ "Sample5_Form1_combo1" ] '
+' }';
Esempio di label di pannello modificabile dinamicamente da programma
E’ possibile modificare dinamicamente la label di un pannello da programma invocando come action della response la
seguente API
xlabel(<absolutePanelId>,<labelId>)
Esempio:
<action name="xlabel('1_F0_WIN_Sample8_Sample8Panel','LabelFromServer')"/>
dove 'LabelFromServer' viene cercata nel dizionario come label e in assenza restituita com’e’ e usata per
l’intestazione del pannello
Esempio di gestione larghezza e altezza
E’ possibile definire alcune proprietà di stile per il pannello (width e height)
Esempio:
Nel pannello HH:MM (figura A) è stata impostata la larghezza a 100 per “avvicinare” i due campi HH e MM, in caso
contrario il pannello ocuuperà il 100% della larghezza e i campi, in celle separate si ritroverranno ben distanziati.
diz["PNL_Sample4HHMM"]='{"id":"Sample4HHMM", "label":"Sample4HHMM", … "style":"{width:100}" '
Esempio di pannello con bordo trasparente per pannelli privi di etichetta
E’ possibile avere un pannello con bordo trasparente per mantenere un eventuale allineamento con pannelli presenti nella
stessa finestra e provvisti di bordo.
E’ sufficiente specificare la parola chiave TRANSPARENT come valore della proprietà label. (figura A)
diz["PNL_Sample4"]='{"id":"Sample4", "label":"TRANSPARENT", …
Esempi di pannelli di tipo tabbed:
Pannello tabbed con 2 sottopannelli
diz["PNL_RdPTabbed"]='{ id:"RdPTabbed", "type":"tabbed", "label":"DynaAddressTabbed",
"style":"position:relative;top:100;left:100;width:100%;height:100%;"'
+','+
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 35 di 167
' "panels":[ '
+diz["PNL_RdPPanel"]
+','
+diz["PNL_RdPRowsList"]
+' ] '
+' } ';
Pannello tabbed : abilitazione/disabilitazione linguetta tabbed
E’ possibile abilitare o meno la linguetta del tabbed
xenableTab(<#pagina da selezioanare>, true|false [,<id del tabbed>])
richiamabile anche come action nella response.
Esempio:
All’uscita campo disabilitare la pagina 2 del tabbed in cui il campo è posizionato
$d2("FLD_Sample10SelectTabField", "row:1, col:0, onblur:'xenableTab(2,false)' ")
Esempio:
Emettere come postAction il seguente comando per disabilitare la pagina 1 del tabbed con id='mySampleTabbed'
<postActions>
<action name="xenableTab(1,false,'mySampleTabbed')"/>
</postActions>
Selezione di una pagina del tabbed
E’ possibile selezionare la pagina di un tabbed mediante l’API dell’UIEngine
xselectTab(<#pagina da selezioanare>[,<id del tabbed>])
richiamabile anche come action nella response.
Esempio:
All’uscita campo passare alla pagina 2 del tabbed in cui il campo è posizionato
$d2("FLD_Sample10SelectTabField", "row:1, col:0, onblur:'xselectTab(2)' ")
Esempio:
Emettere come postAction il seguente comando per passare alla pagina 1 del tabbed con id='mySampleTabbed'
<postActions>
<action name="xselectTab(1,'mySampleTabbed')"/>
</postActions>
Creazione differita di una pagina del tabbed
E’ possibile realizzare un tabbed in cui alcune pagine non siano create al momento dell’aperura della window;
è sufficiente specificare la property creation:'deferred' nella definizione del panello usata per definire una pagina del
tabbed. Al click sulla linguetta del tabbed il pannello viene creato ed eventualmente inizializzato.
E’ opportuno non avere riferimenti dall’esterno ad informazioni presenti nel pannello che potrebbero non essere ancora
state inizializzate.
Esempio:
diz["PNL_SampleTabbed"]='{"id":"SampleTabbed","type":"tabbed","label":"SampleTabbed",
"style":"position:relative;top:100; left:100;width:100%;height:100%;"'
+','
+' "panels":['
+$d2("PNL_Sample1String")
+','
+$d2("PNL_SampleList", " creation:'deferred' " )
+','
+$d2("PNL_Sample1Num", " creation:'deferred' " )
+','
+$d2("PNL_Sample1Combo", " creation:'deferred' " )
+' ] '
+' } ';
Esempio di pannello di tipo grid
Esempio:
diz["PNL_RdPGrd"]='{ id:"RdPGrd", "type":"grid", "label":"DynaAddressGrd",
"style":"position:relative;top:100;left:100;width:100%;height:100%;"'
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 36 di 167
+','+' "panels":[ '+diz["PNL_RdPPanel"]+',' +diz["PNL_RdPRowsList"]+' ] ' +' } ';
Esempio di pannello di tipo list
Consultare il paragrafo relativo alle liste.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 37 di 167
2.5.3 Field
XFIELD
Oggetto:campo di editazione
Sintassi: diz[“FLD_nomecampo”]
Attributo
Sintassi/Note
Opzionale/
Obbligatorio
id
se non definito, assume lo stesso valore di attrname
Opzionale
attrname
nome del parametro nella request,
Obbligatorio
type

non definito

combobox

label

textarea

file (upload)
value
contiene l’eventuale valore di default del campo;
Opzionale
Opzionale
se type=combobox è l’indice dell’elemento preselezionato
values
se type=combobox è la chiave per accedere ai valori
consentiti
Opzionale
se non definito è un combobox con valori dinamici caricati a
runtime dalla response
size
se type=combobox è il numero di elementi da visualizzare
Opzionale
datatype
Indica il tipo di dato. Valori ammessi:
Opzionale
DATE, DATE10,DECIMAL
style
Opzionale
label
Stringa o riferimento a risorsa
Opzionale
labelStyle
Indica la posizione della etichetta del campo,
Opzionale
se non definito essa non è visualizzata.
Valori ammessi: top,left
mandatory
non definito o “true”
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Opzionale
Pagina 38 di 167
disableonnew
non definito o “true”
Opzionale
disableonchange
non definito o “true”
Opzionale
uppercase
non definito o “true”
Opzionale
visibility
non definito o “true”
Opzionale
campo e/o descr non visibile
display
non definito o “true”
Opzionale
campo e/o descr non costruito
filled
Se definita attiva il controllo di riempimento del campo all’exitfocus sul campo e in fase di validazione prima del lancio
Opzionale
help
impostando questa proprietà si attiva l’help
valori consentiti “true” oppure ”chiave_di_dizionario”
Opzionale
menu
contiene la chiave del menu contestuale associato al campo
Opzionale
pf
chiave della definizione di un ReferencedObject nel dizionario
pfparms
lista parametri da passare al ReferencedObject
parzializzazione (additionalWhere)
note
nome del parametro nella request (attrname) del campo
“note” associato al campo
per
la
Opzionale
Opzionale
Proprietà agganciabili al campo a livello di definizione
del pannello
row
Riga
col
Colonna
span
Numero colonne su cui debordare
tabIndex
TabIndex
mask
usato per controllare il valore di un campo
Esempio: campo di tipo ‘Cliente’ dotato di campo descrizione (‘FLD_DESCR’), obbligatorio, con un metodo da
eseguire all’exitfocus ('URL_RdP_CheckCustomer', già nel dizionario) con un suo stile.
diz["URL_RdP_CheckCustomer"]='../CheckAction.do?xmethod=checkCustomer';
diz["FLD_RdPCliente"]='{"id":"RdPCliente","attrname":"CDCSO","pf":"RO_Clienti","mandatory":"true,"label":"CLIENTE","l
abelStyle":"left", "onblur":"xcheck('+ "'" + 'URL_RdP_CheckCustomer'+ "'" + ')", "descr":"FLD_DESCR" ,
"style":{"size":6,"maxlength":6} } ';
Esempio: Associazione generalizzata della descrizione ad un campo
E’ stata semplificata la definizione della descrizione associato ad un campo e dell’eventuale referencedObject.
E’ ora possibile definire delle tipologie generalizzate di campi descrizione (senza attrname) e referenziarli nella definizione
del campo.
diz["FLD_GenericDescription50"]='{"style":{"size":30,"maxlength":50}} ';
diz["FLD_Sample2Customer"]='{"attrname":"CDCSO2", …, "descr":"FLD_GenericDescription50" } ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 39 di 167
Il campo Sample2Customer sarà seguito da un campo descrizione di 30 char e con attrname CDCSO2_xdescr.
Esempio: campo di tipo combobox e lista
diz["LBL_IT_COMBOVALUES_1st"]="Uno";
diz["LBL_IT_COMBOVALUES_2nd"]="Due";
diz["LBL_IT_COMBOVALUES_3rd"]="Tre";
diz["LBL_IT_COMBOVALUES_4th"]="Quattro";
diz["FLD_COMBO1"]='{id:"COMBO1",
values:"COMBOVALUES", type:"combobox",
"attrname":"combo1" } ';
diz["FLD_COMBON"]='{id:"COMBON",
values:"COMBOVALUES", type:"combobox", size:3,
"attrname":"combon"} ';
Esempio di campi collegati ad un campo predefinito
I valori di tali campi saranno inclusi nella richiesta all’esecuzione di operazioni sul campo predefinito. Ad esempio il
CHECK all’exit focus del campo name vedrà aggiunte alla sua request la stringa
&date=valoredelcampo_date&date10= valoredelcampo_date10
diz["URL_PARMS_DynaAddressPanel_id"]='["DynaAddressPanel_Form1_nome","DynaAddressPanel_Form1_codfisc"]’;
Esempio di help
Modificata la logica di attivazione che ora avviene solo impostando la proprietà help nella definizione del campo
Modalità consentite: help:”true” oppure help:”chiave_di_dizionario”
Esempio
diz["HLP_IT_COMBON"]='combo con valori predefiniti…';
diz["HLP_EN_COMBON"]='combo with predefined values…';
diz["FLD_SampleComboN"]='{"id":"COMBON","attrname":"combon", type:"combobox", help:"true", …"} ';
diz["HLP_IT_HelpIdNotRelatedToFldId"]='combo con valori dinamici…';
diz["HLP_EN_HelpIdNotRelatedToFldId"]='combo with dynamic values….';
diz["FLD_SampleComboV"]='{ "attrname":"combov", type:"combobox”, help:"HelpIdNotRelatedToFldId" …} ';
Esempio di combobox dinamico
E’ possibile generare dinamicamente su server valori e le label usate da un combobox e restituirli nella response
secondo la seguente sintassi
<item name="combov" value="A~APPROVATO;;!R~RESPINTO" ></item>
dove APPROVATO e RESPINTO sono le label che appariranno, A e R i valori reali del campo ed il ! indicherà
eventualmente l’opzione selezionata
Il combo box dovrà essere definito nel dizionario in questo modo
diz["FLD_SampleComboV"]='{ type:"combobox", "attrname":"combov" } ';
o
diz["FLD_SampleComboV"]='{ type:"combobox", "attrname":"combov", "size":5} ';
I casi possibili sono:
<item name="combon" value="N" ></item>  un solo valore selezionato
<item name="combon" value=" ;;S" ></item>  più valori selezionati
<item name=" combon " value="!A~APPROVATO;;!R~RESPINTO;;S~SOSPESO" ></item>  reimposta il combo con
nuove opzioni di cui 2 selezionati
<item name="combon" value="" ></item>

ignorato
Esempio di textarea
Con gestione dell’obbligatorietà, lunghezza massima e indicazione della lunghezza testo alla digitazione
Esempio
diz["FLD_SampleTextarea"]='{ "attrname":"textarea", "mandatory":"true", "type":"textarea" , "maxlength":"3",
"rows":5, "cols":60 } ';
Esempi di Label
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 40 di 167
Il componente XField permette di implementare anche il concetto di label in modo etremamente flessibile.
Riassumendo, la label può essere




Testo isolato
Testo isolato
Associato ad
Associato ad
statico
dinamico
un campo, opzionale, (informazione statica)
un campo, opzionale, (informazione dinamica)
caratterizzato da uno stile di default o personalizzabile.
Nell’esempio 8 presenta alcuni di questi casi
Esempio di testo isolato statico
Usato per inserire un commento o una informazione predefinita. Si dichiara nel modo seguente
diz["FLD_SampleSubject"]='{ "type":"label", "labelStyle":"left", labelStyle:"width:100%" } ';
L’assenza dell’attributo “value” lo identifica come statico.
Esempio di testo isolato dinamico
Usato per visualizzare una label il cui valore dipende dall’operazione in atto. Si dichiara nel modo seguente:
diz["FLD_SampleDynalabel"]='{ "attrname":"dynalabel" , value:"dynamic label", "type":"label" } ';
Esempio di Associato ad un campo, opzionale, (informazione statica)
E’ la label che precede un campo il cui valore è risolto in base alla locale dai dizionari.
Opzionale perché attivabile solo se è presente l’attributo labelStyle.
Tale attributo può assumere i seguenti valori:

“top”

”left”,

properties di stile, esempio: "width:70;position:top"
La posizione top pone la label sopra il campo, la left a sinistra, inoltre con le properties è possibile variare le altre
carattistiche (per esempio la larghezza che se non impostata è quella di default: 100px)
Esempio di Associato ad un campo, opzionale, (informazione dinamica)
Come il precedente con la possibilità dal server di variarne il contenuto, usando i metodi delle Action disponibili per
produrre una response del tipo
<data>...
<item name="CDCSO" value="000100" label="Cliente di spedizione 2" ></item>
...</data>
Esempio di label dinamica
Realizzata usando un campo di input con attributo "type":"label".
Può essere statica impostando l’attributo “value”=”testo statico” o dinamica; in questo caso il valore può essere
impostato dalla parte server dell’applicazione con le stesse modalità degli altri campi di input.
Esempio:
diz["FLD_DYNALABEL"]='{ "attrname":"dynalabel" , "type":"label" , "value":"testo statico" } ';
Esempio:
diz["FLD_DYNALABEL"]='{ "attrname":"dynalabel" , value:"dynamic label", "type":"label" } ';
e nella response dovrà essere presente
<data>
<item name=" dynalabel" value="etichetta dinamica" ></item>
</data>
Esempio di XFIELD di tipo file (per UPLOAD)
Realizzato con , ovvero Input tipo file per l’upload, necessario inserirlo in un suo form dedicato.
diz["FLD_SampleFileupload"]='{"attrname":"file2upload" , type:"file" } ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 41 di 167
Esempio di associazione del componente “Note” ad un campo
E’ possibile associare ad un campo un commento definendo la proprietà note nella definizione nel dizionario.
diz["FLD_SampleFieldWithNote"]='{ ..."attrname":"FLDWITHNOTE", "note":"NOTE1", "... } ';
Il valore di questa proprietà è l’attrname del commento; sarà quindi il nome del paramentro nella request.
La response sarà di questo tipo:
Esempio di un campo di tipo “nota” con attrname NOTE1 avente come valore un testo di 2 righe:
<item name="NOTE1" value="rigo1
rigo2" ></item>
Graficamente apparirà l’icona
accanto al campo.
Il componente “note” potrà essere invocato dal campo
stesso con l’acceleratore CTRL-N o cliccando sull’icona.
Per chiudere la finestra senza salvare, cliccare sull’icona
apposita senza salvare o con CTRL-K
Per memorizzare (non salva su server) cliccare sul
dischetto o CTRL-S.
Campo Note: proprietà valore
E’ possibile associare nella definizione del campo commento nel dizionario un valore statico o locale-dipendente.
diz["FLD_Sample4Image"]='{"id":"Sample4Image… "note":"sample4imageurl", notevalue:"Attivo", … } ';
oppure
diz["LBL_IT_DATE"]='Data';
diz["FLD_Sample4Image"]='{"id":"Sample4Image… "note":"sample4imageurl", notevalue:"DATE", … } ';
Campi con proprietà mask
E’ possibile definire una proprietà sul campo per controllare che il valore inserito sia compatibile con una maschera
deifnita per mezzo di una espressione regolare.
Es.
All’exit focus si vuole controllare che il valore nel campo sia compatibile con l’ora nel formato xx:yy (xx=0..24 e
yy=0..59)
Bisogna impostare l’espressione regolare relativa
^(20|21|22|23|[01]\d|\d)(:)[0-5]\d$
nella proprietà mask del campo:
diz["FLD_SampleString09"]='{"attrname":"Sample1Field09", "constraint":"^[0-9:]$",
"mask":"^(20|21|22|23|[01]\d|\d)(:)[0-5]\d$", "labelStyle":"width:300px;position:left",
"style":{"size":5,"maxlength":5} } ';
Gestione proprietà style per i field
E’ possibile impostare da dizionario la proprietà HTML style per un field.
diz["FLD_SampleCustomerStatus"]='{"id":"SampleCustomerStatus", "type":"combo", "attrname":"customerstatus",
"style":{"background":"#FF8000", "color":"#FFFFFF" }, "refcol":"ANCL200F.ATA12","labelStyle":"left" } ';
Esempio di XFIELD di tipo time
E’ disponibile la prima versione del componente per inserire l’ora in diversi formati.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 42 di 167
Derivato da un oggetto dojo, mantiene alcune caratteristiche come il controllo sulla digitazione e l’emissione del
messaggio di errore sulla destra del campo.
Offre un limitato supporto ad alcune funzionalità aggiuntive ACGv4 (onblur,onfocus,onkeyup). Non supporta altre
funzioni tipo help,…
Per definire nel dizionario questo tipo di campo aggiungere la proprietà type:"time"
ed eventualmente il parametro format (opzionale) che può avere i seguenti valori
format:"HH:mm”
format:"HH:mm:ss"
format:"hh:mm:ss:SSS"
Se non specificato si assume il formato format:"HH:mm” (tipo 23:59)
Esempio:
diz["FLD_SampleTime1"]='{"attrname":"time1",
type:"time",
labelStyle:"left",
format (default HH:mm)", "style":{"size":20,"maxlength":20} } ';
label:"Time
senza
diz["FLD_SampleTime2"]='{"attrname":"time2", type:"time", labelStyle:"left", label:"Time HH:mm:ss",
format:"HH:mm:ss" } ';
diz["FLD_SampleTime3"]='{"attrname":"time3", type:"time", labelStyle:"left", label:"Time
hh:mm:ss:SSS con onblur", format:"hh:mm:ss:SSS" } ';
diz["PNL_SampleTime"]='{ "id":"SampleTime", "label":"SampleTime", "formId":"Form1", '
"cols":5, "style":"position:relative;top:100;left:100;width:100%;height:100%;"'
' +' "fields":[ ' +
$d2("FLD_SampleTime1", "row:0, col:0 ")
+','+ $d2("FLD_SampleTime2", "row:1, col:0 ")
+','+ $d2("FLD_SampleTime3", "row:2, col:0, \"onblur\":\"alert('lancio onblur')\" ")
+']'
+','
+' "bar":{row:5, col:0, span:2, "buttonstyle":"width:100;" } '
+','+' "actions":[ '+
$d("ACT_Sample2_save")
+']'
+' , '
+' "url":"URL_Sample2Servlet" '
+' } ';
+' "rows":5,
+ ' ,
diz["WIN_SampleTime"]= '{"window":{ "id":"SampleTime", "width":700, "height":500, "title":"Time",
+ ' "panels":[ '+ diz["PNL_SampleTime"]+' ] '+' }'+' }';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 43 di 167
2.5.4 XAction
XACTION
Oggetto: Action
Sintassi: diz[“ACT_nomeazione”] || diz[“ACT_nomepannello_nomeazione”]
Operazioni predefinite:
Attributo
Sintassi/Note
Opzionale/
Obbligatorio
id
Opzionale
label
Stringa o riferimento a risorsa
Opzionale
Onclick
Comando o stringa comando
Opzionale
Se non definito, invocato xsend che invia una richiesta
ajax all’url definito
Esempio:
"onclick":"mysend()"
url
url da invocare
Opzionale
se non definito viene preso quello del XPANEL
se url del XPANEL non definito, preso quello della XWIN
se url di XWIN non definito, errore a runtime
se url inizia con:
WIN: la pagina andrà in finestra ACG Vision4
URL: in finestra browser esterna
disableonnew
non definito o “true”
Opzionale
disableonchange
non definito o “true”
Opzionale
non definito o “true”
Opzionale
visibility
campo e/o descr non visibile
display
non definito o “true”
Opzionale
campo e/o descr non costruito
Proprietà agganciabili
definizione del pannello
al
tasto
a
livello
di
Row
Riga (se non presente la Action Bar)
Col
Colonna (se non presente la Action Bar)
Span
Numero colonne supero (se non presente la Action Bar)
tabIndex
TabIndex
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 44 di 167
Il nomeazione è usato per attivare implicitamente alcuni comportamenti. Ad esempio nomeazione
viene aggiunto alla request come parametro addizionale
<url>&xmethod=<nomeazione>
semprechè non sia già presente e cablato nell’url stesso.
Esempio:
diz["ACT_DynaAddress_SAVE"]='{'
+'
"id":"ACT_DynaAddress_SAVE"'
+', "label":"ACT_DynaAddress_SAVE"'
/*opzionale, se non definita viene usata la chiave
*/
/*opzionale,se non definita viene usata <nomeazione> */
+', "onclick":"mysend"'
/*opzionale, standard xsend */
+', "url":"../DynaAddress.do?xmethod=SALVA"'
/*opzionale */
+' } ';
Tutte le proprietà sono opzionali perché alcune di esse vengono costruite a partire dalla chiave e
possono far riferimento a informazioni eventualmente già disponibili a livello superiore.
Pertanto sarebbe possibile avere un pannello che includa fra le actions un’azione, la cui definizione
non è presente nel dizionario, purchè sia specificato l’url da invocare a livello di pannello o di
window.
Il nomeazione è usato anche per recuperare la definizione e i comportamenti delle azioni standard.
Si dicono standard le azioni:
new,edit,view,delete,print,copy,save,savenew,saveclose,close,undo,reload,export
Per esse

è precaricata nel dizionario la label

la posizione prevista è nella toolbar dell’XPANEL mediante l’icona

l’icona è fornita, del tipo /images/<nomeazione>.gif

l’ordine è ridefinibile in base alla sequenza fra le actions del XPANEL
Per ottenere azioni non standard è sufficiente usare un <nomeazione>
standard.
non incluso nella lista
1) Metodo invocato al click
se non definito viene usato il metodo standard xsend che gestisce la composizione della request con
gli eventuali parametri e la sottomissione della stessa come richiesta AJAX.
2) Url da invocare
è definito come proprietà di XACTION
altrimenti viene preso quello del XPANEL
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 45 di 167
se url del XPANEL non definito, preso quello della XWIN
se url di XWIN non definito, errore a runtime
Esempi di azione
diz["ACT_DynaAddress_SAVE"]='{'
+' id:"ACT_DynaAddress_SAVE"'
+','
+' "label":"ACT_DynaAddress_SAVE"'
+','
+' "url":"../DynaAddress.do"'
+' } ';
diz["ACT_SAVE"]='{id:"SAVE","label":"SAVE","onclick":"
eseguire"} ';
diz["PNL_DynaAddress"]='{
"tabIndex:0") }
id:"DynaAddressPanel…
+
metodo
javascript
da
$d2("ACT_DynaAddress_READ",
Oggetto XACTION (bottone) apre finestre ACG Vision4o separate
Come nel menu ad albero, anche il bottone nei pannelli ACG Vision4ha la possibilità di aprire nuove
finestre ACG Vision 4 o URL in finestre separate., usando i noti prefissi (WIN: e URL:)
diz["URL_PARMS_Sample8_4INTLINK"]='["Sample8_Form1_CDCSO"]';
diz["ACT_Sample8_4INTLINK"]='{"label":"4INTLINK", "url":"WIN:http://www.ibm.com",
"style":"width:120;" } ';
diz["URL_PARMS_Sample8_4EXTLINK"]='["Sample8_Form1_CDCSO"]';
diz["ACT_Sample8_4EXTLINK"]='{"label":"4EXTLINK",
} ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
"url":"URL:http://www.ibm.com"
Pagina 46 di 167
Possibilità di modificare lo stile del singolo bottone
Sovrascrivendo quello impostato a livello di actionbar.
diz["PNL_Sample8"]='{ "id":"Sample8",'
....
+','+' "bar":{row:4, col:0, span:2,
+','+' "actions":[
"buttonstyle":"width:80;" } '
'+
$d2("ACT_Sample_SAVE", " help:'SAVEonPanel7Help'
")
+','+ $d2("ACT_Sample8_4INTLINK")
+','+ $d2("ACT_Sample8_4EXTLINK", " \"style\":\"width:160;\" ")
+']' +' } ';
Validazione disattivabile sulle actions
Le action possiedono una proprietà che permette di non eseguire la validazione all’invocazione.
Nell’esempio la seconda azione di tipo save non richiama la validation.
diz["PNL_Sample5"]='{ "id":"Sample5", "label":"SamplePanel",
'
' "actions":[
'+ …
$d2("ACT_Sample_save")
+','+ d2("ACT_Sample_save", " id:'exec,no validation', validation:'false' " )
+'] } ';
Identificazione delle action di tipo "Nuovo" o "Lista" dalla Cronologia
Come da standard ACGv4, più nodi del menu ad albero possono essere identificati da stringhe del
tipo “Nuovo”/”Lista”. Nella “Cronologia” però queste azioni non sono identificabili perché tutte
caratterizzate dalla stessa stringa “Lista”.
E' possibile inserire nel dizionario una ulteriore etichetta, nella sintassi come da esempio, che verrà
visualizzata solo nella Cronologia.
Esempio: se
diz["LBL_IT_4ANFO200FList"]="Lista";
basta aggiungere la seguente definizione
diz["LBL_IT_SECONDARY_4ANFO200FList"]="Lista Fornitori";
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 47 di 167
2.5.5
Liste
Liste (PersistentFilters)
Le ACG Vision4sono dotate di un macrocomponente denominato PersistentFilters, che permette di
impostare ed eseguire query parametriche complesse.
Le query usano una definizione di base, creato a design-time mediante un wizard.
Tale definizione di base è un file xml, posizionato nella cartella
<root>\ WEB-INF\classes\com\ibm\acg\xml
dell’applicazione web, definisce la lista dei campi, i nomi delle tabelle interessate, le condizioni di
ordinamento, di selezione (anche dinamica), di join/union, numero max di record e per pagina,...
Query parametriche utente
L’utente finale ha la possibilità di creare a runtime delle interrogazioni proprie denominate “query
parametriche utente” in cui applicare condizioni di visualizzazione, selezione, ordinamento che si
applicano su quelle impostate nel file di definizione di base citato nel paragrafo precedente.
Tale gestione è possibile usando la toolbar delle liste
che offre le operazioni di:

Ricerca nelle liste

Esecuzione query default

Riesecuzione query corrente

Riesecuzione query corrente con nuova richiesta parametri (solo per le query dinamiche)

Nuova query

Modifica query

Lista query

Stampa risultato query

Impostazioni di stampa

Export risultato query
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 48 di 167
Dal pannello “Lista queries” è possibile creare una nuova query, modificare, copiare o cancellare la
query selezionata. E’ possibile definire una query utente di default che sarà richiamata al lancio della
lista al posto di quella descritta nella definizione di base. Inoltre è possibile selezionare quelle
preferite mentre il superutente avrà la possibilità di definire una query di tipo public ovvero
disponibile per tutti gli utenti.
Dal pannello “Crea/Modifica query” è possibile creare la query impostando gli attributi da
visualizzare, le condizioni di selezione (anche dinamiche) e di ordinamento, ...
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 49 di 167
Il componente per la gestione delle query utente è stato realizzato in una finestra dedicata che
contiene tutte le funzionalità già note (lista delle query utente disponibili, creazione e modifica delle
stesse, esecuzione di prova,…)
In più consente, sulla lista delle query disponibili, il lancio di una query nel pannello della finestra
che lo ha aperto.
Per esempio il ReferencedObject presenta la combo con le query preferite, l’utente apre la “Gestione
query utente” e crea una nuova o richiama una esistente ma non preferita dalla lista di tutte le query,
la sua esecuzione avverrà nel ReferencedObject.
Tale componente è disponibile su tutte le liste prodotte con i “PersistentFilters”.
Richiamo rapido a query predefinite tramite combo
Un combo contenente i nomi delle query utente definite come preferite, è posizionato nella lista dei
risultati ed integrato nel messaggio relativo allo stato della query.
Al cambio della selezione viene invocata la query selezionata.
Se la query eseguita non è tra le preferite, questa viene aggiunta temporaneamente nel combo per
coerenza con il messaggio.
Ordinamento a richiesta sulle liste
E’ disponibile l’ordinamento a richiesta da parte dell’utente sul risultato di una lista o query utente.
Quando l’utente clicca sull’intestazione della colonna viene attivato l’ordinamento sulla stessa,
visualizzato con un’icona tipo ; cliccando nuovamente si ottiene l’ordinamento inverso; per tornare
alla situazione iniziale è necessario rieseguire la query con l’operazione di reload.
Se la lista conta una sola pagina, tutti i risultati solo sul client e l’ordinamento viene eseguito sul
browser, altrimenti viene rieseguita la query con l’aggiunta della condizione di ordinamento; tale
condizione non si aggiunge ma sostituisce eventuali condizioni di ordinamento cablate o definite sulla
query.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 50 di 167
Formato visualizzazione liste
E’ possibile variare dinamicamente la visualizzazione della lista per una più agevole consultazione in
caso di colonne numerose o intestazioni molto lunghe.
La funzione è attivabile espandendo o cliccando su una intestazione e mediante un click nella prima
cella in alto a sinistra
è possibile scegliere (ciclicamente) fra diverse modalità di visualizzazione
(visualizzazione standard, ridotta ai primi 3 caratteri, minima, su più righe e successivamente di
nuovo la standard).
La modalità scelta è valida per tutte le liste di tipo PersistentFilters ed è memorizzata nel cookie
dell’applicazione. Cancellando la cache del browser o puntualmente il cookie viene ripristinata la
visualizzazione standard.
Ricerca nelle liste
Permetta la la gestione della ricerca all’interno delle liste.
Dopo aver eseguito una query, essa e’ attivabile con due modalità:
1) facendo click sul pulsante di ricerca presente nella toolbar delle liste.
2) facendo click su una colonna per selezionarla e usando la combinazione di tasti Ctrl ed F.
La window di ricerca
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 51 di 167
contiene i seguenti campi:
 il testo da cercare;
 il check button Intera Stringa (Whole Word) che permette di specificare se cercare l’intera
parola;
 il check button Maiuscolo/Minuscolo (Case Sensitive) che specifica se la ricerca deve essere
o meno di tipo CASE Sensitive;
 il pulsante Cerca (Find): facendo click su di esso viene effettuata la ricerca e viene
visualizzata la pagina che contiene il testo ricercato;
 il pulsante Evidenzia (Highlight): facendo click su di esso le celle della tabella contenenti il
testo ricercato verranno evidenziate in giallo (la ricerca viene effettuata esclusivamente sulla
vista corrente);
 la combo box “Seleziona colonne” contiene la lista di tutti i campi della tabella ottenuti dalla
response. In particolare, se è utilizzata la prima modalità di attivazione della window di ricerca
(click su pulsante ) il campo selezionato in lista è “All columns” e la ricerca viene effettuata
sull’intera tabella; se è utilizzata la seconda modalità di attivazione (click su colonna e Ctrl-F)
verrà automaticamente selezionata la colonna in questione e la ricerca verrà esclusivamente
effettuata sulla stessa.
Funzionalità: Export del risultato di una query
La funzione di export permette di scegliere il tipo di file su cui esportare i dati (excel, xml, csv e csv123), il formato, il numero di record da considerare, etc
Funzionalità: Settaggi di stampa
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 52 di 167
Questa funzionalità che permette di settare le caratteristiche della stampa per una determinata query.
E' possibile settare:

lo stile del file con una delle seguenti opzioni: master.xls, masterBlue.xls e masterRed.xls;

il formato della pagina con formato A4, Letter, Legal, Folio, Quarto, Note, A3, A2.
E' inoltre possibile inserire una nota e un messaggio che verranno inseriti nel frontespizio del
documento stampato.
2.5.5.1 Referenced Objects
Di seguito vi sono una serie di indicazioni per l'utilizzo ottimale del componente Referenced Object.
Esempio di attivazione semplificata ReferencedObject
Si può attivare il referencedObject specificando solo
diz["RO_Sample2Customer"]='{"file":"AAC0","key":["cdcli","rascl"],"show":["stato",
"cdcli","rascl"] }'
omettendo gli attrname dei campi in cui scaricare i valori (refFields); gli attrname saranno desunti
dall’attrname del campo su cui è stato attivato il referencedObject (CDCSO2 e CDCSO2_xdescr)
Questa modalità d’uso richiede che la parte servente mappi l’attributo della descrizione
CDCSO2_xdescr.
con
Esempio di passaggio parametri al ReferencedObject
E’ possibile invocare la lista del RO passando uno o più valori di parzializzazione, definibili inline.
As esempio per implementare una lista “a partire da”, il file xml sottostante al refobj contiene una
additionalWhere del tipo " ANCL200F.CDCLI like '?%' " e il dato da passare è contenuto nel campo
con attrname CDCSO2.
diz["RO_Sample2GenericCustomer"]='{ "file":"AAC0a", "key":["cdcli","rascl"],
"show":["stato","cdcli","rascl"] }'
diz["FLD_Sample2Customer"]='{"attrname":"CDCSO2", "labelStyle":"left",
"mandatory":"true" ,
"pf":"RO_Sample2GenericCustomer", "pfparms":"[\'CDCSO2\']",
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 53 di 167
"onblur":"xcheck('+"'"+'URL_SampleCustomerServlet'+"'"+')"
"descr":"FLD_GenericDescription50" } ';
,
Altre modalità di utilizzo del ReferencedObject
Mediante il doppio click sul titolo del ReferencedObject, è possibile massimizzarlo a tutto schermo.
E' possibile definire:
 i campi che compongono la chiave del record selezionato
 i campi in cui scaricare i valori della chiave del record selezionato
 le colonne da visualizzare
 la where
diz["RO_SampleCustomer"]='{ "file":"AAC0", ’+
‘ "key":["cdcli","rascl","procl"], ’+
‘ "refFields":["CDCSO", "CDCSO_rascl"], ’+
‘ "show":["loccl","cdcli","rascl"], ’+
‘ "where":" cdcli like \'!key%\' " , ’+
‘ "sort":"loccl DESC" }';
Attivazione funzione di gestione query utente per il ReferenceObject
E’ possibile richiamare la funzione di “Gestione query utente” dal referenced Object che apparirà in
una finestra separata.
Attraverso la “Gestione query utente” sarà possibile creare, modificare le query utente associate a
quel ReferencedObject (più precisamente le query utente associate al file .xml associato al
ReferencedObject).
In questo modo sarà possibile creare delle query più vicine all’uso dell’utente finale, con eventuali
parzializzazioni ed ordinamenti, ed averle a disposizione nel combobox delle query preferite.
Richiamo rapido a query preferite mediante combobox per il ReferenceObject
Si fa notare la presenza di un combobox contenente i nomi delle query utente definite come preferite.
Il componente è posizionato nella lista ed è integrato nel messaggio relativo allo stato della query.
Al cambio della selezione viene invocata la query selezionata.
Se la query eseguita non è tra le preferite, questa viene aggiunta temporaneamente nel combo per
coerenza con il messaggio.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 54 di 167
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 55 di 167
2.5.5.2
Navigazione
E’ la possibilità fornita all’utente di passare da un set di informazioni ad un altro secondo regole
predefinite. Per informazione di partenza si intende ad esempio la chiave di un record in una lista, il
contenuto di un campo, un’azione,…L’informazione di arrivo può essere una nuova lista, il risultato
di un calcolo, il lancio di una funzione, ecc.
I percorsi e le modalità di ogni navigazione sono definiti nel dizionario.
Di seguito sono presentati due esempi di navigazione fra liste: il primo, semplificato, è realizzato con
il passaggio dei campi definiti come chiave nella lista di partenza. Nel secondo esempio viene passato
come parametro il contenuto di una o più celle del record selezionato nella lista di partenza.
Esempio 1
Supponiamo di realizzare un percorso di navigazione che
lista dei clienti  lista bolle per il cliente selezionato  lista delle righe per la bolla selezionata
 lista delle registrazioni contabili per il cliente selezionato
e di rendere tale percorso accessibile dal menu dell’applicazione.
Innanzitutto ricordiamo che nel dizionario la relazione fra nodo e sottonodi per strutture ad albero (quali il menu
dell’applicazione, il popup menu o la navigazione)è realizzata secondo la sintassi
diz["NAV_nomeLogicoOggetto"]='nomeLogicoAzione[|nomeLogicoAzione]';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 56 di 167
Aggancio al menu ad albero
Nel nostro esempio si deve aggiungere un nodo al
4SamplesNAVMenu con una sola azione: la lista dei clienti:
menu
ad
albero
dell’applicazione
con
identificativo
// 4SamplesMenu
diz["NAV_4SamplesMenu"]="4AppSamplesMenu|4SamplesWINMenu|4SamplesLinksMenu|4SamplesNAVMenu";
diz["LBL_IT_4SamplesMenu"]="Esempi";
Da questo nodo vogliamo invocare la lista dei clienti:
diz["NAV_4SamplesNAVMenu"]='PFAAC0';
diz["LBL_IT_4SamplesNAVMenu"]="Navigazione";
La lista dei clienti si ottiene definendo PFAAC0 come richiamo di una action
di tipo PF
che fa uso di un file di definizione xml AAC0 presente nella cartella
<acgv4>\WEB-INF\classes\com\ibm\acg\xml
che sulla lista da produrre siano imposti dei campi chiave (anche diversi da quelli impostati nel file di definizione)
che sia applicata una condizione di ordinamento
che sulla lista prodotta associ un menu di navigazione (PFAAC0menu)
// navigazione tipo definita su informazioni di tipo “Cliente”
diz['ACT_PFAAC0']='{id:"PFAAC0", type:"PF", file:"AAC0", "key":["cdcli"], "show":["cdcli","rascl"], "sort":"cdcli",
"menu":"PFAAC0menu" }';
diz['LBL_IT_PFAAC0']="Lista Clienti";
Sulla lista dei clienti abbiamo attivato la navigazione PFAAC0menu che ora andremo a definire
diz["NAV_PFAAC0menu"]='PFBOTE|XCLGX05';
In maniera analoga ora devo definire l’azione PFBOTE e le sue caratteristiche.
PFBOTE usa come file file BOTE.xml con 8 colonne da visualizzare (proprietà show) con 2 colonne che sono da
considerarsi campi chiave su questa lista (proprietà key), con una condizione di ordinamento su 2 colonne e con una
selezione fatta usando la chiave passata.
diz["LBL_IT_PFBOTE"]="Bolle per cliente";
diz['ACT_PFBOTE']='{id:"PFBOTE", type:"PF", file:"BOTE", "key":["nrreb","anneb"],
"show":["tpdcb","cdcsb","nrreb","anneb","dattb","rareb","gbatb","attnb"], "sort":"tpdcb DESC,cdcsb " , "where":" cdcsb
= \'!key\' " , "menu":"PFBOTEmenu" }';
Per il menu PFBOTEmenu indicato sono definiti i percorsi di navigazione possibili:
diz["NAV_PFBOTEmenu"]='PFBORI';
L’azione PFBORI viene definita in questo modo: file BORI.xml con condizione di where sui 2 campi chiave passati
diz["LBL_IT_PFBORI"]="Righe bolla";
diz['ACT_PFBORI']='{id:"PFBORI", type:"PF", file:"BORI" , "where":" nrres = !key AND annes = \'!key\' " }';
Applicando le regole suddette si potrà definire l’altra navigazione (lista delle registrazioni contabili per il cliente
selezionato).
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 57 di 167
Navigazione fra liste passando il contenuto di una o più celle
E’ possibile definire una navigazione più flessibile rispetto a quella standard che, ricordiamo, è basata sul passaggio di
informazioni che sono definite come chiave del record selezionato.
In questa nuova modalità non viene passata la chiave ma il contenuto di alcune celle del record selezionato, in base ad
una definizione presente nel dizionario.
Prima di tutto si definisce sulla lista di partenza il menu contenente tutte le navigazioni possibili (standard e non). La
sintassi di tale definizione rimane la stessa
diz["NAV_nomeLogicoOggetto"]='nomeLogicoAzione[|nomeLogicoAzione]';
come pure la definizione della lista di partenza e quella di arrivo.
La novità consiste nella presenza nel dizionario di una voce che nel suo nome lega la lista di partenza e quella di arrivo
e il cui valore è una lista di nomi di colonne nel seguente formato
diz[“URL_PARMS_<listaPartenza>-<listaArrivo>]=
[ “<nometabella>.<nomecampo1>” [,“<nometabella>.<nomecampoN>”] ]
Esempio:
Dalla lista delle righe dei documenti bolla si vuole risalire ai movimenti a magazzino relativi all’articolo e al magazzino
del record corrente alla lista dei clienti dell’agente presente nella riga del documento bolla.
La lista delle righe dei documenti bolla non ha chiave predefinita.
Si realizza un menu contestuale ("menu":"PFBORI") sulla lista delle righe bolle PFBORI.
Questo menu ha 2 navigazioni (diz["NAV_PFBORI"]='PFMOMAARTMAG|PFCLAG';)
Le navigazioni sono azioni di tipo PF con le condizioni di where opportune.
I parametri da passare sono definiti nel dizionario (es. diz["URL_PARMS_PFBORI-PFCLAG"])
// --- PFCLAG
diz["LBL_EN_PFCLAG"]="Agent's customers";
diz["LBL_IT_PFCLAG"]="Clienti dell'agente";
diz['ACT_PFCLAG']='{id:"PFCLAG", type:"PF", file:"AAC0"
"where":" cdage = \'!key\' " , "menu":"PFBORI" }';
,
"show":["cdcli","rascl","loccl","procl"],
"sort":"procl",
// lista campi chiave da passare a questo filtro, provenienti da altra lista
// diz["URL_PARMS_<lista di partenza>-<lista di arrivo>"]=' [ "<campo lista di partenza>" [,"<campo lista di
partenza>"] ] ';
diz["URL_PARMS_PFBORI-PFCLAG"]=' [ "BORI200F.CDAGS" ] ';
// --- PFMOMAARTMAG
diz["LBL_EN_PFMOMAARTMAG"]="Warehouse mov for item and warehouse";
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 58 di 167
diz["LBL_IT_PFMOMAARTMAG"]="Movimenti magazzino per articolo e magazzino";
//esempio navigazione da 2 celle non chiave
diz['ACT_PFMOMAARTMAG']='{id:"PFMOMAARTMAG",
type:"PF",
file:"MOMA"
,
"show":["cdpar","cdmag","nrmov","cddet","cdcom"], "sort":"cdpar, cdmag", "where":" cdpar = \'!key\' AND cdmag =
\'!key\' " }';
// lista campi chiave da passare a questo filtro, provenienti da altra lista
// diz["URL_PARMS_<lista di partenza>-<lista di arrivo>"]=' [ "<campo lista di partenza>" [,"<campo lista di
partenza>"] ] ';
diz["URL_PARMS_PFBORI-PFMOMAARTMAG"]=' [ "BORI200F.CDARS","BORI200F.CDMGS" ] ';
// --- PFBORI
diz["LBL_EN_PFBORI"]="Shipping doc rows";
diz["LBL_IT_PFBORI"]="Righe bolla";
diz['ACT_PFBORI']='{id:"PFBORI", type:"PF", file:"BORI" , "where":" nrres =
"menu":"PFBORI" }';
!key AND annes =
\'!key\' " ,
// menu sulla lista PFBORI
diz["NAV_PFBORI"]='PFMOMAARTMAG|PFCLAG';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 59 di 167
2.5.5.3 Liste con selezione multipla
Questo comportamento è attivabile impostando la proprietà "selection":"multiple" nella definizione
di un pannello che deve ospitare una lista.
La stessa modalità può essere usata nelle liste usate nella navigazione; in questo caso è la definizione
della ACTion di tipo lista che conterrà la proprietà selection.
La richiesta al server conterrà il parametro di nome sel con la serie delle chiavi dei record
selezionati.
Esempio di log della richiesta per le selezioni effettuate sull’immagine precedente
param:xform
1_F0_WIN_Sample3List_Sample5SelectableList
param:xwin
1_F0_WIN_Sample3List
param:sel
222
param:sel
3
altriparametri
…
Esempio di attivazione per un pannello che contiene una lista
In un pannello contenitore sono definite due liste, la seconda di queste ha la proprietà per la selezione multipla attivata.
Definizione del pannello SampleList:
diz["URL_SampleList"]=''+xPFContext+'/pf/XGenericTable.jsp?queryDefinitionFileName=com/ibm/acg/xml/XRRCT.xml&
';
diz["PNL_SampleList"]='{ "id":"myId", "label":"LIST", "init":"true", "style":"height:100%;width:100%;" '
+' , "url":"URL_SampleList", "menu":"MNU_SampleList" } ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 60 di 167
Utilizzo del pannello SampleList nel pannello contenitore attivando la selezione multipla:
diz["PNL_Sample3ContainingPanel"]='{
"style":"position:relative;width:100%;height:100%;", '
"id":"Sample3ContainingPanel",
+' "formId":"Form1", '
+' "collapsed":"false", label:"Pannello in pannello", '
+' "panels":[ '
+$d2("PNL_Sample3List",' "id":"Pannello2", "label":"Sample3", … )
+','
+$d2("PNL_SampleList", ' "id":"Sample5SelectableList", "selection":"multiple", collapsed:"true" ')
…}
Esempio di attivazione su una lista usata nelle navigazioni
Supponiamo di avere una navigazione fra liste e su una delle liste interessate si desideri attivare la selezione multipla
per poter eseguire una certa operazione (presente nel flying menu) su più record.
La lista delle bolle ottenuta mediante una ACTion di tipo PF avrà la selezione multipla per supportare per esempio la
ristampa delle stesse (azione presente nel menu PFBOTE) e che sul server potrà eseguire l’operazione usando le chiavi
dei record selezionati passati come valori multipli del parametro sel.
diz["LBL_EN_PFBOTE1"]="Shipping doc for customer";
diz["LBL_IT_PFBOTE1"]="Bolle per cliente ";
diz['ACT_PFBOTE1']='{id:"PFBOTE", type:"PF", file:"BOTE", "selection":"multiple", "key":["nrreb","anneb"],
"show":["tpdcb","cdcsb","nrreb","anneb","dattb","rareb","gbatb","attnb"],
"sort":"tpdcb
DESC,cdcsb
DESC"
,
"menu":"PFBOTE" }';
Selezione multipla impostabile via programma
E’ possibile selezionare/deselezionare le scelte su una lista a selezione multipla dinamicamente a programma.
Vi sono 2 metodi; il primo seleziona/deseleziona tutti i checkbox, il secondo opera sul singolo record identificato
attraverso la sua chiave.
xselectAll(<nome form>, true|false)
xselect(<nome form>,<chiave>,true|false)
Esempio:
<action name="xselectAll('1_F0_WIN_RdPList_RdPList',true)"/>
<action name="xselect('1_F0_WIN_RdPList_RdPList',100,true)"/>
Selezione multipla sul ReferencedObject
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 61 di 167
E’ possibile associare ad un campo di input standard o di tipo TEXTAREA un referencedObject con la possibilità di scelta
multipla.
Cliccando sui checkbox e alla conferma la lista delle chiavi dei record selezionati vengono riversati nel campo di
riferimento.
La lista è una stringa unica in cui le chiavi sono separate dalla ,
Esempio di risultato
chiave1[,chiaveN]
dove la chiave è una stringa.
Si ricorda che nel caso di chiavi composte da più informazioni esse sono del tipo
chiaveParte1[|chiaveParteN]
Il componente ReferencedObject a selezione multipla contiene nella prima cella delle intestazioni un checkbox che
Seleziona/deseleziona tutto
Inverte la selezione effettuata
2.5.5.4
Rielaborazione Liste
Questo comportamento consente di rielaborare il risultato di una query e di evidenziare il contenuto
informativo di una colonna o della singola cella, di attivare funzioni specifiche.
E’ attivabile inserendo una definizione nel dizionario che faccia riferimento alla colonna.
Essa può essere identificata da
<queryId>_<xmlfile>_<nomeTabella>.<nomeColonna>
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 62 di 167
La definizione sarà valida solo per la query specificata sul file xml indicato
<xmlfile>_<nomeTabella>.<nomeColonna>
La definizione sarà valida solo tutte le query sul file xml indicato
<nomeTabella>.<nomeColonna>
La definizione sarà valida sempre, per la colonna indicata
In questo modo si possono attivare comportamenti diversi in base alle diverse esigenze applicative.
Ad esempio è possibile:





modificare lo stile di una intera colonna (sfondo, colore testo,…)
modificare lo stile a livello di singola cella di una colonna
aggiungere una icona (il logo della società) sulla destra o sulla sinistra del testo di una cella
sostituire completamente il valore della cella (lo stato il cui valore è I di IMMESSO) con una
icona, mantenendo l’accessibilità al valore attraverso il flying-text
sostituire/aggiungere una icona che è un bottone per lanciare funzioni specifiche con il
passaggio di parametri (valore della cella corrente e chiave del record selezionato)
Nell’esempio in figura vi è una sostituzione sulla “colonna codice cliente di spedizione” con una
aggiunta sulla destra di una icona (il logo dell’azienda).
Sulla colonna “stato” è invece impostata una sostituzione mediante funzione che restituisce una
sostituzione con uno stile con sfondo verde chiaro per lo stato blank e una sostituzione del valore I
con l’icona relativa.

eseguire le operazioni di sostituzione sopra descritte come risultato di una funzione (scritta in
javascript) che modifichi le caratteristiche delle singole celle di una colonna.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 63 di 167
Nell’esempio che segue sulla colonna “fido” è impostata una sostituzione che fa uso di una
funzione che restituisce una definizione di sostituzione diversa a seconda che il valore sia <200
(sfondo grigio), <1000 (sfondo giallo), >1000 (sfondo rosso, testo bianco).
Inoltre è stata attivata l’opzione action che permette di rendere l’icona come un bottone e di
associare l’invocazione di un metodo javascript.
Nell’esempio cliccando sul bottone si ottiene un messaggio di conferma (con il passaggio del
valore della cella e della chiave del record selezionato) e successivamente il lancio di una gestione
ACGv4 con il passaggio di tali parametri.
Esempi:
Sintassi:
diz["REF_[<queryid>_][<xml>_]<table>.<column>"] = '{
["type":"icon",
"src":"<iconsrcReference>",]
["position":"right|left",]
["style":"...",]
["func":"<functionReference>"] }';
// OVR CDCSO
// replace text with icons mapped through in a ACGV4 relative src path
diz["REF_RRCT3V4F.CDCSO"]='{ "type":"icon", "position":"right",
"src":"RRCT3V4FCDCSO" }';
diz["REF_RRCT3V4FCDCSO"]="/products/E01/images/logo_!value.gif";
// replace text with icons mapped through in an external src path
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 64 di 167
diz["REF_RRCT3V4F.CDCSO"]='{ "type":"icon", "position":"right",
"src":"RRCT3V4FCDCSO" }';
diz["REF_RRCT3V4FCDCSO"]="http://127.0.0.1:9080/acgv4/products/E01/images/logo_!v
alue.gif";
// OVR campo FLIMO di RRCT3V4F
// change the text style, for the column, for all xml, for all queries
diz["REF_RRCT3V4F.FLIMO"]='{ "style":"background:#BBFFBB;color:#FF0000;"
}';
// change the text style, for the column, for an xml, for all queries
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{
"style":"background:#BBFFBB;color:#FF0000;"
}';
// change the text style, for the column, for an xml, for DEFAULT query
diz["REF_DEFAULT_XRRCT.xml_RRCT3V4F.FLIMO"]='{
"style":"background:#BBFFBB;color:#FF0000;" }';
change the text style, for the column, for an xml, for a query named ovr
diz["REF_ovr_XRRCT.xml_RRCT3V4F.FLIMO"]='{
"style":"background:#BBFFBB;color:#FF0000;"
}';
// replace text with icons mapped through values
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{ "type":"icon", "src":"RDPSTATUS" }';
// replace text with icons mapped through values, with a style
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{ "src":"RDPSTATUS", "type":"icon",
"style":"background:#FFFFBB;color:#FF0000;" }';
// replace text with icons mapped through values, appending it before text
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{ "src":"RDPSTATUS", "type":"icon",
"position":"left", "style":"background:#BBFFBB;color:#FF0000;" }';
// replace text with icons mapped through values, appending it after text
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{ "src":"RDPSTATUS", "type":"icon",
"position":"right", "style":"background:#BBFFBB;color:#FF0000;" }';
// values mapped to image names, if extension is not defined, .gif appended
diz["REF_RDPSTATUS_D"]="/images/iDraft";
diz["REF_RDPSTATUS_I"]="/images/iSubmit";
diz["REF_RDPSTATUS_V"]="/images/iOK";
diz["REF_RDPSTATUS_"]="/images/iDef";
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 65 di 167
// replace text with an override definition via a js function
diz["REF_XRRCT.xml_RRCT3V4F.FLIMO"]='{ "func":"RDPSTATUSFUNC" }';
diz["REF_RDPSTATUSFUNC"]="_checkRDPSTATUS('!value','!key')";
function _checkRDPSTATUS(aValue,aKey){
//confirm('\n_RDPSTATUSFUNC:\n'+aValue+'\n'+aKey);
switch (aValue) {
case 'I':
return '{ "src":"RDPSTATUS", "type":"icon",
"style":"background:#BBFFBB;color:#FF0000;"
}';
break;
default:
return '{ "src":"RDPSTATUS",
"style":"background:#EEFFEE;color:#FF0000;"
}';
break;
}
}
// replace text with an override definition via a js function
// attiva solo sulla query fido
diz["REF_fido_AAC0.xml_ANCL200F.FIDOCE"]='{ "func":"FIDOCLIENTE" }';
// solo su tutte le query
diz["REF_AAC0.xml_ANCL200F.FIDOCE"]='{ "func":"FIDOCLIENTE" }';
diz["REF_FIDOCLIENTE"]="_checkFIDO('!value','!key')";
function _checkFIDO(aValue,aKey){
//xshowMsg('\n _checkFIDO :\n'+aValue+'\n'+aKey+'...'+parseInt(aValue));
if(parseInt(aValue.replace(/$$thouSep/gi,''))>500){
return '{ "type":"icon", "src":"/images/_err.gif",
"position":"right", "style":"background:#FF0000;color:#FFFFFF;",
"action":"_warningFIDO(\'!key\',\'!value\')" }';
}
else{
if(parseInt(aValue)>200){
return '{ "style":"background:#F9F793;color:#000000;" }';
}
else{
return '{ "style":"background:#EEEEEE;color:#000000;" }';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 66 di 167
}
}
}
function _warningFIDO(aKey,aValue){
if(confirm('Attiva procedura fido eccessivo (' + aValue + ' EUR) \n cliente
'+aKey+' ')){
xcrtWIN('F0','WIN_Sample2', '['+aKey+']');
}
}
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 67 di 167
2.5.6 Componente HeaderRows
2.5.6.1 Definizione di un oggetto HeaderRows
Un pannello di tipo headerRows è un panello che contiene una lista di righe, che non necessariamente
sono il risultato di una query su database (come ad esempio le liste di tipo Persistent Filters). Le righe
di un pannello hr, posso essere ad esempio il risultato di una elaborazione, il contenuto di un file di
lavoro o rappresentare degli oggetti di business.
Per creare un pannello hr è necessario dichiarare nel dizionario un oggetto PNL con property
type=”headerRows”, ad esempio:
diz["PNL_HEADERROWS"]='{"id":"HEADERROWS",
"type":"headerRows","style":"overflow:auto;width:100%;height:100%;",'
+'"linked":"DETAILP","rowsForPage":"4","menu":"MNU_HeaderRows",'
+'"collapsed":"false",'
+'"fields":['+$d2("FLD_CampoRow1")
+','+$d2("FLD_CampoRow2")
+','+$d2("FLD_CampoRow3")
+','+$d2("FLD_CampoRow4")
+','+$d2("FLD_CampoRow5")
+','+$d2("FLD_CampoRow6")
+']'
+', "actions":[ '
+ $d("ACT_Newrow")
+','+ $d("ACT_EditRow")
+ ','+$d("ACT_Deleterow")
+'] }';
Nella situazione più semplice un pannello hr contiene campi e azioni. I campi rappresentano le
colonne della lista, le azioni sono i bottoni della toolbar della lista.
Le proprietà che caratterizzano un pannello hr sono:






checkbox: se a false viene nascosto il checkbox sulla prima colonna
linked: il pannello di dettaglio della riga (se esiste)
rowsForPage: numero righe max per pagina
menu: il menu contestuale sulla lista
editable: se a true, la lista è editabile
rowNumber: se è uguale a true, viene visualizzato un contatore di righe
2.5.6.2 Gestione di una lista HeaderRows lato Controller
Vediamo ora come gestire lato server una lista di tipo hr, ovvero cosa è necessario scrivere nella
action che gestisce la window, per caricare le righe della lista e lavorare su di esse (creare una nuova
riga, modificarla, cancellarla ecc.).
2.5.6.3 Response xml
I dati necessari a gestire il pannello di tipo headerRows sono contenuti nella sezione della response
<hr>...</hr>.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 68 di 167
2.5.6.4 Caricamento iniziale delle righe della lista HeaderRows
Per caricare o forzare il ricaricamento di tutte le righe della lista, è necessario valorizzare il parametro
datas della response tramite il metodo setHeaderRowsParms(actionForm, numberOfElements,
currentPage, datas) della classe AddRowInfo:
AddRowInfo addrinfo = getRowInfo(request,actionForm);
oppure
AddRowInfo addrinfo = getRowInfo(request,actionForm,id del pannello hr);
nel caso sia necessario indicare esplicitamente l’id del pannello di tipo headerRows (ad esempio se si
voglio gestire più liste in una stessa response o perché il valore di xform è blank).
addrinfo.setHeaderRowsParms(actionForm, "" + element.getRows().size(), "1",
getDatas(element),"");;
Nell’ultima parametro (datas) deve essere passata la stringa che contiene le informazioni delle righe,
opportunamente formattate.
Se il parametro datas è uguale a blank, le righe non vengono rimosse. Per forzare la rimozione di
tutte le righe della lista, è necessario richiamare il metodo xclearRowList (v. lista funzioni) come
PREACTIONS/POSTACTIONS.
2.5.6.5 Formattazione della stringa dati da inviare alla lista
Il valore da passare al parametro datas (xdatas) deve essere formattato secondo la seguente sintassi:





ogni riga della lista deve essere separata dalla stringa “~;;”
ogni colonna della singola riga deve essere separata dal carattere “~”
nella prima posizione della riga va indicata la chiave (se esiste), che si vuole associare alla
riga. Se non viene indicata, ogni riga verrà identificata con la posizione sulla lista. In caso di
chiavi multiple, per convenzione ogni chiave viene separata dal carattere “|”
nella seconda posizione può essere indicato il title, se non indicato, verrà utilizzata come title
la chiave. Tale valore viene utilizzato nel menu del pannello
a seguire vanno inseriti i valori delle colonne
Ad es. per una lista di 4 colonne ogni riga dovrà essere così formata:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 69 di 167
chiave1|chiave2~title1|title2|title3~valore_colonna1~val_col2~val_col3~val_col4~;;
Se non si vuole indicare un text-title:
chiave1|chiave2~~valore_colonna1~val_col2~val_col3~val_col4~;;
Se non si vuole indicare né il title né la chiave della riga:
~~valore_colonna1~val_col2~val_col3~val_col4~;;
Per formattare secondo tale sintassi le righe da inviare ad una lista, sono disponibili alcune utility. In
particolare viene fornita la classe ListCreator che permette di creare e viceversa di leggere la stringa
delle righe della lista.
Se quindi dobbiamo preparare il valore da passare al parametro datas possiamo definire nell’action un
metodo getDatas() che ci restituirà la stringa delle righe, formattata secondo la sintassi
precedentemente descritta. Questo metodo prenderà in input l’oggetto della testata da cui reperire tutte
le righe della lista:
public String getDatas(Rrct300f header){
Collection rows=header.getRows();
ListCreator lc = new ListCreator();
if (rows == null || rows.size() == 0)
return "";
Rrcr300f elem = null;
for (Iterator it = rows.iterator(); it.hasNext();) {
elem = ((Rrcr300f) it.next());
addEntryToList(elem, lc);
}
return lc.getData();
}
All’interno del metodo, ciclando sulle righe associate alla testata, viene richiamato il metodo
addEntryToList per ogni riga. Tale metodo, da implementare nella action, formatta le informazioni
delle righe tramite ListCreator:
private void addEntryToList(Rrcr300f row, ListCreator lc) {
lc.addEntry();
lc.addKey(""+row.getId().getNrrmr()).addKey(""+row.getId().getNrimr());
lc.addTitle(""+row.getId().getNrrmr())
.addTitle(""+row.getId().getNrimr());
lc.addValue(""+row.getId().getNrrmr())
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 70 di 167
.addValue("" + row.getDtcrr())
.addValue(row.getCdarr().trim())
.addValue(row.getDsr1r().trim())
.addValue(row.getUnmsr().trim())
.addValue(""+row.getQtorr());
}
In questo esempio ogni riga ha una chiave composta (nrrmr e nrimr) e la lista sarà composta di sei
colonne.
La stringa restituita dal metodo getDatas andrà a valorizzare la property datas della sezione
<rows></rows> nella response, ad esempio:
Per effettuare l’operazione inversa, ovvero reperire le informazioni delle righe a partire dalla stringa
che ci arriva dal client, possiamo implementare nella Action la funzione getEntriesFromList:
private HashMap getEntriesFromList(String datas) {
HashMap hm =
new HashMap();
String[] rows = datas.trim().split(“~;;”);
for (int i=0;i<rows.length;i++) {
ListCreator lc = new ListCreator();
lc.addEntry();
lc.addEntryFromString(rows[i]);
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 71 di 167
Rrcr300fId key = new Rrcr300fId();
key.setNrrmr((new Integer(((String)lc.getKey(1)).trim())).intValue());
key.setNrimr((new Integer(((String)lc.getKey(1)).trim())).intValue());
Rrcr300f row = null;
row = new Rrcr300f();
row.setId(key);
if (lc.getValue(1)!=null)
row.setDtcrr((new
Integer(((String)lc.getValue(1)).trim())).intValue());
if (lc.getValue(2)!=null)
row.setCdarr(((String)lc.getValue(2)).trim());
if (lc.getValue(3)!=null)
row.setDsr1r(((String)lc.getValue(3)).trim());
if (lc.getValue(4)!=null)
row.setUnmsr(((String)lc.getValue(4)).trim());
if (lc.getValue(5)!=null)
row.setQtorr(new BigDecimal(((String)lc.getValue(5)).trim()));
hm.put(lc.getKeys(), row);
}
return hm;
}
Nella funzione, per prima cosa viene divisa la stringa nelle stringhe delle singole righe (tramite il
metodo split a cui viene passata la stringa separatore delle righe ‘~;;’), e, per ogni stringa di riga,
viene invocato il metodo addEntryFromString della classe ListCreator. A questo punto è possibile
reperire le informazioni della riga tramite i metodi getKey, getTitle e getValue sull’oggetto
ListCreator opportunamente inizializzato. L’indice da passare a tali metodi, rappresenta l’ordine con
cui si sono inserite le informazioni nel metodo addEntrytoList.
2.5.6.6 Inserimento o modifica di una riga della lista
Per inserire nuova riga o modificare una riga esistente della lista è necessario utilizzare la classe
AddRowInfo. Ad esempio:
AddRowInfo rowInfo = getRowInfo(request, actionForm);
rowInfo.addData(actionForm, ""+getDatas(row, logon),""+ row.getId().getNrrmr(),
"");
in questo caso si sta inserendo una riga della lista, passando nel metodo addData il valore della riga
come secondo parametro e la posizione dove inserire la riga nella lista come terzo parametro.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 72 di 167
Se si voleva invece aggiungere la riga sempre alla fine della lista:
rowInfo.addData(actionForm, ""+getDatas(row, logon),"", "");
mentre per emettere la riga in stato draft o in errore:
rowInfo.addData(actionForm, ""+getDatas(row, logon),"", AddRowInfo.STATUS_DRAFT);
rowInfo.addData(actionForm, ""+getDatas(row, logon),"", AddRowInfo.STATUS_ERROR);
Nella response verrà aggiunto un elemento <row></row> per ogni riga aggiornata/aggiunta, nella
sezione <rows></rows> della lista opportuna. Ad esempio:
Se invece si vuole inserire la riga in una posizione particolare della lista, si può indicare nel metodo
addData il numero di riga.
Per modificare una riga esistente, si deve utilizzare lo stesso metodo, con la differenza di indicare
come chiave della riga la chiave della riga da modificare. In questo caso il componente aggiornerà la
riga esistente nella lista con i nuovi valori di colonna passati.
2.5.6.7 Cancellazione di una riga
Esistono due modalità per cancellare una o più righe della lista:
1) utilizzare il metodo xdeleterow (precedentemente descritto) passando il metodo della action che
dovrà gestire la cancellazione della riga/righe. La lista di chiavi delle righe selezionate per la
cancellazione verrà passata nel parametro KEYS della request (ogni chiave è separata dalla stringa
~;;).
All’interno del metodo indicato sarà poi necessario, per ogni riga la cui cancellazione ha avuto esito
positivo, richiamare il metodo addData, passando la chiave della riga cancellata. Questo è necessario
per indicare nella response la lista delle righe da rimuove sulla lista.
2) impostare lo stato della riga a DELETE tramite il metodo addData
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 73 di 167
2.5.6.8 Gestione del pannello piede
Per gestire un pannello di dettaglio delle righe si può impostare la proprietà linked sia sul pannello
lista che sul pannello piede. Tale proprietà serve ad indicare un legame tra i due pannelli e deve
contenere l’id del pannello piede nella lista, e viceversa l’id del pannello lista nel piede. Ad esempio:
diz["PNL_OperationsRowsList"]='{ "id":"OperationsRowsList", '
+ ' "label":"OperationsRowsList", '
+ ' "linked":"OperationsRowPanel",'
+ ' "style":"height:150;width:100%;" , '
+ ' "rowsForPage":"5" , '
+ ' "dblclick":"xopenDetail()" '
+ ', "type":"headerRows", '
+
' "fields":[ '
+ $d2("FLD_OperationsRowId")
+ ',' + $d2("FLD_OperationsRowFlag")
+ ',' + $d2("FLD_OperationsStatus")
+ '] '
+ ', "actions":[ '
+ $d("ACT_OperNewrow")
+ ','+ $d("ACT_OperCancelrow")
+ ','+ $d("ACT_OperDelrow")
+ ']'
+ ' } ';
diz["PNL_OperationsRowPanel"]='{ "id":"OperationsRowPanel",
"label":"OperationsRowPanel", "formId":"Form2", "rows":"5", "cols":"5",
"style":"position:relative;top:100;left:100;width:100%;height:100%;"'
+',"enterAction":"SAVEROW",'
+' "linked":"OperationsRowsList",'
+ ' "fields":[ '
+ $d2("FLD_OperationsRowId", "row:1, col:0")
+ ',' + $d2("FLD_OperationsRowFlag", "row:1, col:1")
+ ']'
+ ', "actions":[ '
+ $d("ACT_Operations_saverow")
+ ']'
+ ' } ';
In una situazione standard di window che contiene testata-lista-piede, la testata e la lista saranno
contenute in una unica form, il piede sarà gestito tramite una form differente.
FORM1
TESTATA
LISTA RIGHE
FORM2
PIEDE
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 74 di 167
Nello struts-config saranno definite due action (una per gestire la testata e una per il piede) e le due
form relative, la prima conterrà la lista dei campi della testata, la seconda quelli del pannello di
dettaglio.
Le funzioni che a partire dalla lista prevedono il caricamento dei dati nel pannello piede, dovranno
fare riferimento alla form di quest’ultimo pannello.
Ad esempio supponiamo di voler editare una riga della lista. Tramite bottone della lista o doppio click
sulla riga (se non si tratta di lista editabile), richiamiamo la funzione xsendCheckedDataLista o
xsendCheckedKeysList, a seconda se vogliamo passare al server tutti i dati della riga od
esclusivamente la chiave della riga.
diz["ACT_OperEditRow"]='{ "id":"OperEditRow","icon":"Edt", "label":"Modifica",'+
'"url":"xsendCheckedKeysList(\'../operateRowAction.do?xmethod=editRow\',\Operation
sRowPanel\')" } ';
Nella funzione si dovrà passare come primo parametro il metodo della action relativa alla form del
piede e (se non è stata impostata la proprietà linked) come secondo parametro l’id della form indicata
nel pannello piede. Questo ci permetterà di valorizzare nel metodo richiamato i campi della form del
pannello piede.
2.5.6.9 Gestione di più liste nella stessa response
E’ possibile gestire più liste di tipo hr all’interno di una stessa response indicando l’identificativo
della lista nel metodo getRowInfo. Ad esempio:
AddRowInfo addrinfo1 = getRowInfo(request,actionForm, "PanelList1");
addrinfo.setHeaderRowsParms(actionForm, "", "1", getDatas1(element),"");;
AddRowInfo addrinfo2 = getRowInfo(request,actionForm, "PanelList2");
addrinfo.setHeaderRowsParms(actionForm, "", "1", getDatas2(element),"");;
…
nella response si avrà:
quindi ci sarà all’interno della sezione hr, una sezione rows per ogni differente lista gestita dalla
response. La property name sta ad indicare l’id della lista (o della form se non viene indicato) mentre
in datas ci sarà la lista delle righe da caricare.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 75 di 167
2.5.6.10 Label dinamiche
E’ possibile indicare lato server le label delle colonne della lista utilizzando il metodo addLabels
dell’oggetto AddRowInfo. Anche la classe di utility ListCreator fornisce il metodo addLabel per
creare la stringa di labels da inviare alla lista:
ListCreator lc = new ListCreator();
lc.addLabel("Col
1").addLabel("Col
4").addLabel("Col 5").addLabel("Col 6");
2").addLabel("Col
3").addLabel("Col
addrowinfo.setHeaderRowsParams(actionForm, "5", "1", getDatas(),
lc.getLabels());
2.5.6.11 Modifica del menu di una riga
Per modificare o aggiungere il menu associato ad una riga si possono utilizzare due modi:
1. richiamare come preaction/postaction il metodo xsetRowMenu
2. utilizzare uno dei seguenti metodi della classe AddRowInfo
- addData(DynaActionForm form, String value, String line, String status,
-
String datas, String menu)
addAfter(DynaActionForm form, String value, String arow, String status,
String datas, String menu)
Ad esempio:
AddTreeInfo rowinfo = (AddTreeInfo)getTreeInfo(request, actionForm);
rowinfo.addData(actionForm,key,"","", "","MNU_Treemenu1");
dove in key viene passata o la chiave della riga o il valore di tutta la riga se si vuole aggiornare o
aggiungere una nuova riga.
2.5.6.12 Aggiunta di una riga in posizione successiva alla riga corrente
Se si vuole tramite menu contestuale aggiungere una riga alla lista in posizione successiva alla riga
corrente (ovvero alla riga dove è posizionato il menu), si può utilizzare il metodo:
addrowinfo.addAfter(actionForm, lc.getData(), key, "", "", "");
passando nel secondo parametro il dati della nuova riga, e nel parametro key la chiave della riga sotto
la quale si vuole aggiungere la nuova. La chiave della riga corrente può essere reperita nel parametro
KEYS della request, se nel menu contestuale si è utilizzato il metodo xsendTitleList:
diz["CMD_hr1"]='js:xsendTitleList(\'../TestHRAction.do?xmethod=addRow\')';
2.5.6.13 Creazione di una finestra tramite menu contestuale
Se si vuole lanciare la creazione della finestra utilizzando il menu contestuale della lista e passando
l’informazione di riga, si deve:

dichiarare un cmd del tipo
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 76 di 167


diz["CMD_hr1"]='js:xcrtWIN(\'F1\',\'WIN_Test1\',\'[!key]\' )';
aggiungere il cmd al menu contestuale della lista hr/tree
dichiarare un campo nella proprietà parms della finestra creata (WIN_Test1), dove passare il
parametro della riga.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 77 di 167
2.5.7 Lista Editabile
Una lista editabile è realizzabile con un pannello di tipo headerRows, impostando il parametro
editable a true. Le caratteristiche dei campi di input presenti nella lista (lunghezza, obbligatorietà,
tipologia, ecc.) derivano dalle definizioni degli oggetti di tipo field contenuti nel pannello.
diz["PNL_HEADERROWS"]='{"id":"HEADERROWS", "type":"headerRows",'
+'"style":"overflow:auto;width:100%;height:100%;",'
+'"linked":"DETAILP","rowsForPage":"4","menu":"MNU_HeaderRows",'
+'"collapsed":"false","label":"Lista editabile",'
+'"editable":"true",'
+'"checkbox":"true",'
+'"fields":[
+$d("FLD_CampoRow1")
+','+$d("FLD_CampoRow2")
+','+$d("FLD_CampoRow3")
+','+$d("FLD_CampoRow4")
+','+$d("FLD_CampoRow5")
+','+$d("FLD_CampoRow6")
+']'
+', "actions":[ '
+ $d("ACT_Newrow")
+','+ $d("ACT_Saverow")
+']'
+'}';
2.5.7.1 Dblclick
All’evento di doppio click sulla riga, viene automaticamente associata la funzione di editazione della
riga. Per sovrascrivere tale comportamento è necessario indicare un valore nella property dblclick del
pannello.
Ogni volta che una riga passa dallo stato di editazione allo stato di output, vengono richiamate le
validazioni lato client sui campi della riga.
2.5.7.2 Onedit
Se si voglio inviare invece i dati della riga al momento dell’uscita della riga dallo stato di editazione, è
necessario valorizzare la property onedit. Il metodo indicato nella proprietà sarà richiamato ogni volta
che una riga passa dallo stato di editazione allo stato di output.
diz["URL_TreeChange"]='../ca/SchemiRiclassificaAction.do?xmethod=changeRow';
diz["PNL_ANKR200FTreesp"]='{"id":"ANKR200FTreesp",
"label":"ANKR200FTreesp","init":"true", "rowsForPage":"3",'
© Copyright ACG Srl 2014 Tutti i diritti riservati.
"type":"headerRows",
Pagina 78 di 167
+'"editable":"true","menu":"MNU_RiclassificaSpTreeMenu",'
+'"onedit":"URL_TreeChange",'
...
Nel metodo richiamato verranno passati i dati della riga (ovvero i valori dei campi) tramite il
parametro DATAS.
2.5.7.3 Xsend
Per reperire i dati della lista, si possono utilizzare le stesse funzioni disponibili sulle liste hr
(xsendCheckedKeysList, xsendDataList, ecc.). Oltre alle funzioni tipiche del hr, è possibile utilizzare
la funzione:
xsendEditDataList(aUrl,aFormId,aPnlId)
che permette di inviare al server i dati della riga in editazione, senza rimuovere lo stato di editazione
della riga (come fanno di solito le altre funzioni). I dati possono essere reperiti nel parametro DATAS
della request.
Se invece si vogliono invare solo le righe modificate (individuabili con un flag sulla riga), è possibile
richiamare la funzione
xsendChangedDataList (aUrl,aFormId,aPnlId)
2.5.7.4 Riga in errore
Per mettere una o più righe in stato di errore, si deve per ogni riga richiamare il metodo addData:
rowinfo.addData(actionForm,dati, "","ERROR");
dove nel parametro dati è possibile passare o la chiave della riga o il valore di tutta riga (se si vuole
modificare la riga stessa).
Per rimuovere lo stato di errore, è necessario passare lo stato della riga a blank, oppure utilizzare uno
dei metodi js disponibili.
2.5.7.5 Riga in editazione
Se si vuole aggiungere una riga o modificarla e automaticamente metterla in stato di editazione, si può
utilizzare il parametro STATUS del metodo addData:
rowinfo.addData(actionForm,chiave, "","EDIT");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 79 di 167
Se si vuole mettere la riga in errore e in stato di editazione:
rowinfo.addData(actionForm,chiave, "","EDIT|ERROR");
Qualora si voglia che alcuni dei campi della riga siano di input solo se la riga si trova in inserimento e
non in editazione, si possono sfruttare le proprietà disableonedit e disableonnew del campo, ed
utilizzare lo stato EDIT_NEW (al posto di EDIT) nel caso si stia in inserimento.
2.5.7.6 Combo dinamica su lista editabile
La lista editabile può contenere un campo combo, i cui valori vengono valorizzati dinamicamente lato
server. Per indicare la lista di valori con cui valorizzare la combo, è necessario utilizzare il metodo:
addDisplayInfo(DynaActionForm form,
String item_name, String value)
passando in item_name il valore di attrname del campo combo, ed in value la lista di valori della
combo, secondo la stessa sintassi valida per i campi combobox dinamici.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 80 di 167
Per realizzare un drilldown su una lista di tipo headerRows si deve per prima cosa dichiarare a livello
di dizionario la sotto-lista di drilldown nell’attributo panels della prima lista hr. Tale lista dovrà essere
necessariamente una lista tipo HR. Ad esempio:
diz["PNL_HEADERROWS"]='{"id":"HEADERROWS", "type":"headerRows",'
+'"style":"overflow:auto;width:100%;height:100%;",'
+'"rowsForPage":"4","menu":"MNU_HeaderRows"'
+'"collapsed":"false","label":"prova",'
+'"editable":"true",'
+'"drilldownUrl":"../TestHRAction.do?xmethod=loadSubRows",'
+'"fields":['+$d2("FLD_CampoRow1")
+','+$d2("FLD_CampoRow2")
+','+$d2("FLD_CampoRow3")
+','+$d2("FLD_CampoRow4")
+','+$d2("FLD_CampoRow5")
+','+$d2("FLD_CampoRow6")
+']'
+', "actions":[
'
+ $d("ACT_PROVANewrow")
+']'
+', "panels":['+diz["PNL_HEADERROWSDET"]+']'
+'}';
dove PNL_HEADERROWSDET è a sua volta un pannello di tipo hr.
Nella property drilldownUrl è possibile indicare il metodo della action da richiamare al click sul
bottone di drilldown:
Nel metodo richiamato (loadSubRows) posso recuperare la chiave della riga da cui è partita la
richiesta tramite il parametro della request KEYS:
String keys = request.getParameter("KEYS");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 81 di 167
AddRowInfo rowinfo = getRowInfo(request, actionForm);
rowinfo.addData(actionForm, keys, "", "", getDatas());
Per caricare i dati della sotto-lista, utilizzando la chiave della riga si richiama il metodo
addData(DynaActionForm form, String value, String line, String status, String
datas)
passando nel parametro datas, i dati della sotto-lista.
Una volta caricata la sotto-lista, si può lavorare sulle righe nella stessa modalità di una semplice lista
HR.
Esempio di aggiunta di una riga tramite menu su sotto-lista:
diz["CMD_AddRow "]='js:xsendTitleList
(\'../TestHRRowAction.do?xmethod=addSubRow\')';
diz["MNU_Treemenu2"]='["CMD_AddRow"]';
Nel metodo addSubRow aggiungo un’altra riga, tramite il metodo:
rowinfo.addData(actionForm,dati della nuova riga , "","");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 82 di 167
2.5.8 Drilldown
Per realizzare un drilldown su una lista di tipo headerRows si deve per prima cosa dichiarare a livello
di dizionario la sotto-lista di drilldown nell’attributo panels della prima lista hr. Tale lista dovrà essere
necessariamente una lista tipo HR. Ad esempio:
diz["PNL_HEADERROWS"]='{"id":"HEADERROWS", "type":"headerRows",'
+'"style":"overflow:auto;width:100%;height:100%;",'
+'"rowsForPage":"4","menu":"MNU_HeaderRows"'
+'"collapsed":"false","label":"prova",'
+'"editable":"true",'
+'"drilldownUrl":"../TestHRAction.do?xmethod=loadSubRows",'
+'"fields":['+$d2("FLD_CampoRow1")
+','+$d2("FLD_CampoRow2")
+','+$d2("FLD_CampoRow3")
+','+$d2("FLD_CampoRow4")
+','+$d2("FLD_CampoRow5")
+','+$d2("FLD_CampoRow6")
+']'
+', "actions":[
'
+ $d("ACT_PROVANewrow")
+']'
+', "panels":['+diz["PNL_HEADERROWSDET"]+']'
+'}';
dove PNL_HEADERROWSDET è a sua volta un pannello di tipo hr.
Nella property drilldownUrl è possibile indicare il metodo della action da richiamare al click sul
bottone di drilldown:
Nel metodo richiamato (loadSubRows) posso recuperare la chiave della riga da cui è partita la
richiesta tramite il parametro della request KEYS:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 83 di 167
String keys = request.getParameter("KEYS");
AddRowInfo rowinfo = getRowInfo(request, actionForm);
rowinfo.addData(actionForm, keys, "", "", getDatas());
Per caricare i dati della sotto-lista, utilizzando la chiave della riga si richiama il metodo
addData(DynaActionForm form, String value, String line, String status, String
datas)
passando nel parametro datas, i dati della sotto-lista.
Una volta caricata la sotto-lista, si può lavorare sulle righe nella stessa modalità di una semplice lista
HR.
Esempio di aggiunta di una riga tramite menu su sotto-lista:
diz["CMD_AddRow "]='js:xsendTitleList (\'../TestHRRowAction.do?xmethod=addSubRow\')';
diz["MNU_Treemenu2"]='["CMD_AddRow"]';
Nel metodo addSubRow aggiungo un’altra riga, tramite il metodo:
rowinfo.addData(actionForm,dati della nuova riga , "","");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 84 di 167
2.5.9 Componente Tree View
Per creare un oggetto tree è necessario definire nel dizionario un componente panel, di tipo “tree”:
diz["PNL_TreePanel"]='{"id":"TreePanel", "type":"tree",
"rowsForPage":"3","editable":"true","menu":"MNU_Treemenu",'
+'"onedit":"URL_TreeChange","fields":['
+$d2("FLD_Voce")
+','+$d2("FLD_DescrVoce")
+','+$d2("FLD_Segno")
+','+$d2("FLD_CodiceNota")
+','+$d2("FLD_Cambio")
+'], "style":"width:100%;height:700px;" }';
dove:
- rowForPage indica il numero massimo di righe di primo livello che possono essere
visualizzate su ogni pagina della lista;
- editable indica se le righe dell’albero sono editabili;
- onedit è l’url da richiamare quando si esce dall’editazione di una singola riga (se le righe sono editabili);
diz["URL_TreeChange"]='xsendCheckedDataList(\'../TreeViewAction.do?xmethod=chan
geRow\')';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 85 di 167
-
menu è il flymenu sulle righe dell’albero
//aggiunge una nuova riga, passando nel parametro KEYS il title della riga
//corrente
diz["CMD_tree1"]="js:xsendList(\'../TreeViewAction.do?xmethod=addRow&KEYS=!k
ey\')";
//richiama la cancellazione della riga, passando nel parametro KEYS il
//title della riga corrente
diz["CMD_tree5"]="js:xdeleterow(\'../TreeViewAction.do?xmethod=deleteRow&KE
YS=!key\');";
diz["MNU_Treemenu"]='["CMD_tree1","CMD_tree2",…]';
Per gestire lato server una lista di tipo albero, istanziare la classe AddTreeInfo nel seguente modo:
AddTreeInfo addtreeinfo = getTreeInfo(request, actionForm)
oppure, passando l’identificativo della lista (nel caso in cui il valore di xform è blank o si devono
gestire più liste su diverse form):
AddTreeInfo addtreeinfo = getTreeInfo(request,actionForm,”TreePanel”)
Per caricare inizialmente le righe che comporranno l’albero, si può utilizzare il metodo:
setTreeParams(DynaActionForm form, String numOfElems, String currentPage, String
datas, String labels, ArrayList top, HashMap hierarchy)
che prende in input la stringa (datas) contenente le righe dei nodi e delle foglie che costruiranno
l’albero (la sintassi di tale stringa è la stessa valida per il componente testata-righe), la lista delle righe
al primo livello (top) e infine un HashMap con le informazioni di gerarchia tra i nodi.
Se ad esempio vogliamo costruire il seguente albero:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 86 di 167
NODO
1
NODO
3
NODO
2
NODO
4
NODO
5
LEVEL 1
NODO
6
NODO
7
LEVEL 2
LEVEL 3
dobbiamo passare come nodi TOP (a livello 1) il nodo 1 e 2, e le seguenti informazioni di relazione
tra nodi, indispensabili per la costruzione dell’albero:
nodo 1 ha come figli: nodo3 e nodo 4
nodo 4 ha come figli: nodo 5
nodo 2 ha come figli: nodo 6
nodo 6 ha come figli: nodo 7
Per la valorizzazione dell’ArrayList e della HasMap, è possibile utilizzare i metodi della classe
ListCreator:
getTreeHierarchy()
getTreeTop()
Ad esempio:
AddTreeInfo treeinfo = (AddTreeInfo)getTreeInfo(request,actionForm);
treeinfo.setTreeParams(actionForm, "", "1", lc.getData(), "", lc.getTreeTop(),
lc.getTreeHierarchy());
dove lc è l’oggetto di tipo ListCreator:
ListCreator lc = new ListCreator();
//aggiungo una riga con chiave 1
lc.addEntry();
lc.addKey(1+"");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 87 di 167
lc.addTitle("");
lc.addValue("new row n. "+1)
.addValue("ATTIVO").addValue("* TOTALE dell'ATTIVO")
.addValue("D").addValue("").addValue("");
//imposto la riga corrente (chiave 1) come riga di primo livello:
lc.addTop();
//indico che la riga corrente ha come figli la riga con chiave 3 e //chiave
4
lc.addChild(3+"").addChild(4+"");
//aggiungo la riga con chiave 3
lc.addEntry();
lc.addKey(3+"");
lc.addTitle("");
lc.addValue(3+"")
.addValue("CRED.SOCI").addValue("Crediti
dovuti")
verso
soci
per
versamenti
.addValue("D").addValue("").addValue("");
//aggiungo la riga con chiave 4
lc.addEntry();
lc.addKey(4+"");
lc.addTitle("");
lc.addValue(""+4)
.addValue("IMMOBILIZZI").addValue("Immobilizzazioni")
.addValue("D").addValue("").addValue("");
Per aggiungere una nuova riga all’albero, è possibile utilizzare uno dei seguenti metodi:
-
per aggiungere una riga figlia di un’altra riga:
addChild(DynaActionForm form, String value, String status, String node)
dove node è la riga padre e value il valore della nuova riga
-
per aggiungere una riga prima di un’altra riga e allo stesso livello:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 88 di 167
addBefore(DynaActionForm form, String value, String status, String node)
-
per aggiungere una riga dopo un’altra riga e allo stesso livello:
addAfter(DynaActionForm form, String value, String status, String node)
se invece è necessario aggiungere una riga al primo livello o modificare una riga già esistente (anche
di livello superiore a uno), si può utilizzare il metodo:
addData(DynaActionForm form, String value, String status, String children)
oppure:
addData(DynaActionForm form, String value, String status, String children, String
menu)
dove value è il valore della riga, e children la lista delle chiavi delle figle righe (se presenti), separate
dal carattere ~
Ad esempio:
addrowinfo.addData(actionForm,"0~~0~~ ATTIVO ~~;;",
AddTreeInfo.TOP, "1~2");
E’ inoltre possibile impostare lato server il menù sulla singola riga (che quindi può essere diverso da
quello delle altre righe dell’albero), passando come parametro la chiave della riga (o il valore della
riga stessa) e l’id dell’oggetto menù:
addrowinfo.addData(actionForm,"0","","","MNU_Treemenu1");
2.6 Skin e font
E’ disponibile una funzione di personalizzazione dello stile dell’intera applicazione, utilizzabile da
parte dell’utente finale. Egli può cambiare il tema stilistico (“skin”) generale dell’applicazione e altri
aspetti specifici quali il font e la sua dimensione. Le modifiche sono dinamiche ed immediatamente
fruibili; le preferenze sono memorizzate nel cookie del browser.
La funzione è accessibile cliccando sull’icona “Impostazioni utente”
presente in alto a destra nel
deskop ACG Vision4 o dal menu ad albero seguendo il percorso Strumenti > Impostazioni >
Impostazioni client > Impostazione Client Utente.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 89 di 167
Temi / Skins
I temi a disposizione, nella versione corrente, sono 3:

“Classico” o di default

“Demo” caratterizzato da una maggior cura dell’estetica del desktop, delle icone e dei
pannelli con uso di sfondi grafici, trasparenze, set di icone specifico.

“Classico 2” Simile al “Classico” ma con visibilità migliorata
Immagini dei tre skin a disposizione:
Tema “CLASSICO” (skin 0)
Tema “DEMO” (skin 1)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 90 di 167
Tema “CLASSICO2” (skin 2)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 91 di 167
Tema personalizzato
E’ possibile costruire uno o più temi personalizzati, validi per l’intera applicazione, in aggiunta
ai tre citati nel paragrafo precedente.
Le informazioni relative all’aspetto grafico (foglio di stile ed immagini) devono essere presenti nelle
sottocartelle dell’applicazione acgv4
/addon/skins/0
/addon/skins/1
/addon/skins/2
...
/addon/skins/n
dove il nome della cartella per convenzione è un valore numerico.
Le sottocartelle 0 , 1 e 2 sono già presenti e contengono le informazioni per i tre temi
CLASSICO, DEMO e CLASSICO2. Per quelle personalizzate si consiglia di usare come nome della
cartella il valore da 10 in su.
Questo identificativo è usato per associare il nome dello skin; è usato anche nell’elenco dei temi
nella finestra delle IMPOSTAZIONI CLIENT UTENTE
Esempio:
Si vuole creare un tema a partire da quello CLASSICO2 in cui il testo nei campi disabilitati sia
invertito (chiaro su sfondo scuro. Questo stile avrà come nome PERSONALIZZATO
(CUSTOMIZED in inglese) e sarà disponibile a livello di applicazione a tutti gli utenti.
1) Copiare la cartella
<acgv4>\addon\skins\2
nella cartella
<acgv4>\addon\skins\
e ridenominarla come 10
2) Personalizzare il foglio di stile
<acgv4>\addon\skins\10\ui.css
per esempio inserendo
INPUT.readonly{
background-color:#000066;
border:1px solid #FFFFFF;
}
al posto di
INPUT.readonly{
background-color:#FFFFFF;
font-weight:bold;
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 92 di 167
}
3) Ricercare nel file
/diz/diz.js
la voce
diz["VAL_xCLIENTSkin"]="[0,1,2]";
da usare per aggiungere nella lista degli identificativi numerici degli stili, lo stile personalizzato 10,
ottenendo il nuovo valore di questa chiave
diz["VAL_xCLIENTSkin"]="[0,1,2,10]";
4) Aggiungere nel file
/customized/ext.js
le voci
diz["LBL_IT_xCLIENTSkin_10"]="Personalizzato";
diz["LBL_EN_xCLIENTSkin_10"]="Customized";
diz["VAL_xCLIENTSkin"]="[0,1,2,10]";
5) Dai client (eventualmente cancellando la cache del browser) scegliere da IMPOSTAZIONI
UTENTE il nuovo tema PERSONALIZZATO
NOTA. Se alcuni moduli applicativi o personalizzazioni introducono nuove immagini alla cartella di
base
<acgv4>/images
allora devono essere fornite le corrispondenti immagini nelle cartelle /images/ di ogni skin
\addon\skins\<n>\images
dove n è un valore numerico che identifica i vari stili.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 93 di 167
Variazione tema di default
Qualora si desideri impostare un valore di default del tema diverso da “Classico”, inserire la
riga
UISKIN= valore numerico del tema scelto (es. 1,2..)
in coda al file <root>\WEB-INF\classes\conf\Base.properties, indicando il numero che rappresenta il
tema da utilizzare ad ogni collegamento per ogni utente.
NOTA: Se l’utente finale desidera utilizzare un tema diverso da quello di default definito nel file
Base.properties, potrà modificarlo nella finestra delle IMPOSTAZIONI CLIENT UTENTE. Tali
impostazioni infatti vengono memorizzate nel cookie del browser ed hanno “priorità” rispetto a quella
definita nel file Base.properties e valide dal successivo ricaricamento del desktop.
E’ possibile eliminare queste impostazioni cancellando dalla cache del browser il cookie
relativo (in IE TOOLS/INTERNET OPTIONS/SETTINGS/VIEW FILES/)
Esempio:
Si e’ creato un tema PERSONALIZZATO identificato dal valore 10. Se si vuole che questo tema
diventi quello di default; per fare cio’ occorrera’ inserire , nel file Base.properties , la riga
UISKIN=10
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 94 di 167
2.7 FAQ
Per realizzare un TABBED
definire la proprietà
type:"tabbed"
Per realizzare un pannello contenente più pannelli
diz["PNL_PannelloEsterno"]='{ id:"PannelloEsterno", …
… "panels":[ diz["PNL_Pannello1"] , diz["PNL_ Pannello2"]
]
}
Per realizzare un form unico contenente un tabbed
WIN
CONTAININGPANEL formId, URL,….
TABBED
TABPANEL1
TABPANEL2
diz["WIN_UniFormTabbedWindow"]= '{"window":{'
+
' "panels":[ '
+diz["PNL_UniFormPanelContainingTabbed"]
+' ] '
+' } }';
diz["PNL_UniFormPanelContainingTabbed"]='{ id:"UniFormPanelContainingTabbed", "formId":"FormT",
collapsed:"false", "style":"position:relative;top:100;left:100;width:100%;height:100%;"'
+','
+ ' "panels":[ '
+diz["PNL_UniFormTabbed"]
+','
+diz["PNL_DynaAddress"]
+' ] '
+','
+' "bar":{"buttonstyle":"width:100;" } '
+','+
+' "actions":[ '
+ $d("ACT_UniForm_SAVE")
+ ']'
+' } ';
segue definizione PNL_UniFormTabbed
segue definizione PNL_DynaAddress
Per realizzare una finestra con 2 pannelli uguali (risolvendo i problemi di ambiguità)
Definire in pannello normalmente e usare la funzione $d2 per sovrascrivere l’ID.
diz["WIN_SimpleWindow"]= '{"window":{'
+ ' "panels":[ '
+ diz["PNL_SimplePanel"]
+ $d2("PNL_SimplePanel", "
+','
id:'secondoPannello'
© Copyright ACG Srl 2014 Tutti i diritti riservati.
" )
Pagina 95 di 167
+' ] '
…
+' } }';
Per ottenere il bordo del pannello (con/senza etichetta)
definire la proprietà label del pannello
"label":"",
"label":"NomePannello",
"label":"ChiaveDizionarioPerNomePannello",
Per abilitare l’invocazione di CLOSE alla chiusura di una XWIN
Definire la proprietà url nella window
Esempio:
diz["URL_MyWindow"]='../MyAction.do';
diz["WIN_ MyWindow "]= '{"window":{'…
' "panels":[ ' … +' ] ' +','
+' "url":"URL_ MyWindow " '
+' } }';
oppure
+' "url":"../DynaAddress.do " '
Per passare dei parametri ad una window ed avvalorarne i campi
Invocare la window in questo modo
xcrtWIN('F0','WIN_RdP', ' [ 5,4]' );
o in modo dinamico
xcrtWIN('F0','WIN_RdP', ' [!key,!key]' );
per invocazioni da liste con passaggio di chiavi
definire i campi da avvalorare…
diz["WIN_RdP"]= '{"window":{ "id":"RdPWindow", "width":700, "height":500, '
+ ' "panels":[ '
+diz["PNL_RdPPanel"]
+' ] '
+' }'
+','+
' "parms": [ "RdPPanel_Form1_NRIMO" , "RdPPanel_Form1_NRIM2"] '
+' }';.
Oppure
' "parms": [ "RdPPanel_NRIMO" , "RdPPanel_Form1_NRIM2"] '
Per invocare un metodo specifico della action di STRUTS da un button
Definire:
diz["ACT_DynaAddress_RESTORE"]='{'
+' id:"ACT_DynaAddress_RESTORE"'
+' disableonedit:"true" '
+','
+','
+' "label":"ACT_DynaAddress_RESTORE"'
© Copyright ACG Srl 2014 Tutti i diritti riservati.
+','
Pagina 96 di 167
+' "url":"../DynaAncl200f.do?xmethod=READ"'
+' } ';
Per collassare/espandere una sezione all’esecuzione di una richiesta sul server
Impostare come pre o postActions
dall’dentificativo del pannello.
il metodo xexpand, xcollapse o xtoggle (per alternare i due stati) seguito
Esempio che disabilita un pannello
addPropertyAsVector(actionForm,"xreadonly('BancaPanel','false')", POSTACTIONS);
Esempio di invocazione refresh su una lista
addPropertyAsVector( actionForm, mapping.getProperty("reloadRows"), POSTACTIONS);
Esempio di espansione
addPropertyAsVector(actionForm,
POSTACTIONS);
"xexpand('"+request.getParameter("xwin")+"_DynaAddressList_SPAN"+"')"
,
Per attivare il ReferencedObject su un campo (funzione ? di ACG)
Prerequisito:
file xml dei PersistentFilter nella cartella /WEB-INF/classes/com/ibm/acg/xml/
Attivabile sul campo inserendo nella sua voce nel dizionario la proprietà pf contenente la chiave del dizionario
ReferencedObject.
del
diz["FLD_RdPCliente"]='{"attrname":"CDCSO","pf":"RO_Clienti", …} ';
Il ReferencedObject deve essere definito nel dizionario con le seguenti proprietà




il nome del file xml usato per produrre la lista
i campi di riferimento in cui scaricare i valori del record selezionato (corrispondono agli attrname)
i dataItemName (nel file xml) delle colonne da scaricare
i dataItemName (nel file xml) delle colonne da visualizzare
diz["RO_Clienti"]='{
"file":"AAC0",
"show":["stato","cdcli","rascl"] }'
"refFields":["
CDCSO
","
CDCSO_rascl"],
La funzione è richiamabile sul campo mediante tastiera con CTRL-space o cliccando sull’icona
"key":["cdcli","rascl"],
accanto al campo.
Per aggiungere una voce al menu a tendina
Supponiamo di voler aggiungere una voce di menu al nodo TOOLS, basterà aggiungere in un file
/addon/diz/diz_<miaestensione>.js
diz["NAV_TOOLS"]="...|4MiaGestione"
diz["LBL_IT_4MiaGestione"]="Lancio MiaGestione";
diz["LBL_EN_4MiaGestione"]="...";
diz["CMD_4MiaGestione"]="js:xcrtWIN('F0','WIN_MiaLista');"
Per creare una finestra con lista (da PF), con apertura della finestra di dettaglio al doppioclick
1) INSERIRE IN
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 97 di 167
/WebContent/WEB-INF/source/com/ibm/acg/xml/
gli xml delle liste
2) Personalizzare opportunamente:
MiaLista
MioDettaglio
MIOFILEXML
diz["ACT_DblClickMiaListaPanel"]='{ "id":"ACT_DblClickMiaLista" ,
\'[!key]\' ) " } ';
"url":" xcrtWIN(\'F1\',\'WIN_MioDettaglio\',
diz["URL_MiaLista"]=''+xPFContext+'/pf/XGenericTable.jsp?queryDefinitionFileName=com/ibm/acg/xml/MIOFILEXML
.xml' + USER_AND_PASSWORD + '&';
diz["PNL_MiaListaPanel"]= '{ "id":"MiaListaPanel", "init":"true", '
+' "style":"height:100%;width:100%;" '
+' "url":"URL_MiaLista" '
+' , '
+' , '
+' "dblclick":"ACT_DblClickMiaListaPanel" '
+' } ';
diz["WIN_MiaLista"]= '{"window":{ "id":"MiaListaWindow", "width":700, "height":500, '
+
' "panels":[ '
+diz["PNL_MiaListaPanel"]
+' ] '
+' }'
+' }';
e aggiungerlo in coda ad un diz_4acronimoprodotto.js
3) Aggiungere una voce al menu per lanciare la gestione
diz["NAV_4...Menuesistente"]="...|4MiaGestione"
diz["LBL_IT_4MiaGestione"]="Lancio MiaGestione";
diz["LBL_EN_4MiaGestione"]="...";
diz["CMD_4MiaGestione"]="js:xcrtWIN('F0','WIN_MiaLista');"
Per personalizzare azioni sulle righe del componente TESTATA_RIGHE
E’ possibile aggiungere azioni personalizzate sulle righe selezionate; il comando da eseguire invocherà l’API
xexecrow(aUrl [,aHandler])
che eseguirà un’invocazione ajax verso l’url specificato passando come parametro KEYS gli identificativi delle righe
selezionate; l’handler è opzionale.
Esempio:
diz["ACT_SampleCustomizedHRAction"]='{ "id":"SampleCustomizedHRAction", "icon":"Exp", "label":"Export",
"url":"xexecrow(\'../MyServlet.do?\')" } ';
diz["PNL_Sample"]='{ …actions":[ '+ $d("ACT_SampleCustomizedHRAction")
Per lanciare direttamente una richiesta AJAX da menu
E’ possibile definire una voce di menu (per esempio DIRECTAJAXREQ)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 98 di 167
diz['NAV_NODOMENU]='AZIONE1|AZIONE2|…|DIRECTAJAXREQ';
diz['LBL_IT_DIRECTAJAXREQ']="Richiesta AJAX diretta ";
diz['LBL_EN_DIRECTAJAXREQ']="Direct AJAX request";
diz["CMD_DIRECTAJAXREQ"]="js:xdirectsend('../DynaAddress.do?xmethod=launch')"
Per lanciare una finestra alla risposta dal server
Dall’esempio precedente è possibile invocare il server per ottenere una response ACG Vision4 che contenga nella
sezione <preActions> il comando per istanziare la finestra ed eventualmente nella sezione <data> i dati per
inizializzarla con i valori di default nella stessa richiesta.
<preActions>
<action name='xcrtWIN("F1","WIN_DocumentoVendita" )' />
</preActions>
<postActions>
</postActions>
<data>
<item name="ModalitaPagamento" value="A10" ></item>
<item name="ModalitaSpedizione" value="SP1" ></item>
</data>
In alternativa si può istanziare la finestra con il comando nella sezione <preActions>, senza fornire alcun dato e lasciare
che i pannelli impostati con init=true effettuino le realtive richieste di inizializzazione dei dati al server.
Naturalmente il contenuto delle response presentate deve essere costruito mediante l’invocazione dei metodi forniti
dall’architettura ACG Vision4.
Per impostare il dizionario di un nuovo prodotto/personalizzazione
E’ possibile eliminare ogni dipendenza del dizionario di un prodotto dai diz di base.
Si impostano nel diz_mioprodotto tutte le voci, anche quelle del mioo menu e di aggancio ad nodo base ACG Vision4.
Esempio:
L’albero degli esempi, agganciato al nodo ACG Vision4viene completamente definito in diz_Samples.js.
diz["NAV_4ACGV4"]+="|4SamplesMenu";
// 4SamplesMenu
diz["LBL_EN_4SamplesMenu"]="Samples";
diz["LBL_IT_4SamplesMenu"]="Esempi";
diz["NAV_4SamplesMenu"]="4SamplesWINMenu|4SamplesLinksMenu";
…
diz["FLD_SampleCustomer"]='…
Come inserire o modificare una voce del dizionario
E’ disponibile una API del UIENGINE che permette di inserire/modificare una voce del dizionario
xaddToDictionary(<chiave>,<valore>);
invocabile anche da response per modificare dinamicamente il dizionario in base ad esigenze applicative.
Es.
addPropertyAsVector(actionForm,
POSTACTIONS);
"xaddToDictionary('LBL_IT_AAC0.xml_ANCL200F.CDCLI','Clienti
© Copyright ACG Srl 2014 Tutti i diritti riservati.
VIP')",
Pagina 99 di 167
Da notare che le modifiche apportate varranno da quel momento in poi anche in caso di chiusura e riapertura della
finestra che ne fa uso.
Un ricaricamento mediante
ripristina la situazione iniziale.
o CTRL-R del desktop o allo scollegamento o al lancio di una nuova istanza di browser,
Esempio di operazione in 2 fasi
Supponiamo di voler eseguire un salvataggio in 2 fasi.
L’utente clicca sul SALVA e la richiesta con tutte le info del form viene elaborata dalla parte controller sul server che
emette un comando fra le postAction.
<postActions>
<action name="CMD_SaveConfirm"/>
</postActions>
Tale comando è richiede una richiesta di conferma per il salvataggio definitivo
diz["CMD_SaveConfirm"]="js:if(confirm('Sei sicuro?')){xdirectsend('../DynaAddress.do?xmethod=confirmedsave') }";
Nella richiesta saranno inviati il metodo, l’id della window (xwin), l’id del form (xform) correnti.
E’possibile nel comando far riferimento ad una window o ad un form diversi, in questo caso gli id della window e della
form correnti non saranno inviati.
E’ possibile anche inviare un valore presente nella window sfruttando il meccanisco standard della voce URL_PARMS
associata al comando.
diz["URL_PARMS_SaveConfirm"]=' [ "SamplePanel_Form1_date" ] ';
Nuova funzione “Controllo componenti”
Nel menu “Raccolta informazioni è presente questa voce che stampa nella sesione log tutte le voci del dizionario di tipo
VER_ che indicano la versione dei componenti in uso.
Nuova funzione “Cambio locale EN/IT”
Nel menu “Risoluzione problemi/Controlli” è presente questa voce che permette di passare dalla locale EN a IT per
testare le notazioni anglosassone/latina delle informazioni DATE e NUMERIC.
Introdotto limite al testo nella sezione “Log”
La variabile $$maxlog impostata a 30000 char.
Liste: Introdotto delay sul flyingmenu sulle liste
Quando si abbandona il flyingmenu e si ritorna sulla lista, la chiusura del flyinmenu viene ritardata di circa un secondo.
Se in questo lasso di tempo si ritorna sul flyingmenu la chiusura viene annullata.
Pannelli: Inizializzazione di un pannello mediante esecuzione di metodi javascript
E’ possibile eseguire una inizializzazione via metodi javascript per quelle gestioni in cui non è necessario recuperare
alcuna informazione dal server.
Naturalmente il metodo deve essere disponibile in uno dei dizionari caricati.
diz["URL_xCLIENTSETTINGS"]='js:initializaClientSettings()';
diz["PNL_xCLIENTSETTINGS"]='{ "id":"xCLIENTSETTINGS", "label":"xCLIENTSETTINGS", "init":"true", '
+' "style":"height:400;width:100%;" '
+' , '
+' "url":"URL_xCLIENTSETTINGS" '
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 100 di 167
+' } ';
Sostituzione parametri mediante indice
Finora era possibile definire un url con delle parti variabili (indicate con !key), sostituite dinamicamente con i valori
effettivi (per esempio la chiave di un record di una lista).
In presenza di una chiave composta la sostituzione avviene in modo posizionale (la prima parte verrà sostituita alla
prima occorrenza di !key, e cosi via…)
Con la modifica introdotta è possibile usare la notazione !keyi (dove i può andare da 0 a n-1 dove n sono le parti di una
chiave) in modo da consentire la sostituzione delle singole parti di una chiave composta più volte o in un ordine diverso
da quello posizionale.
"where":" cdmag = \'!key1\' AND cdpar = \'!key0\'
Focus
Il focus è in generale impostato sul primo campo del pannello.
In alcuni casi può essere necessario cambiare questa impostazione.
in fase di costruzione della finestra specificando nel dizionario l’identificativo del campo che deve ricevere il focus
diz["WIN_Sample1"]= '{"window":{ "id":"Sample", "width":700, "height":400 , '
+' "panels":[
+$d2("PNL_Sample1a", " collapsed:'false' ")
+' ] '
+','
+' "focus":"SamplePanel_Form1_field3" '
+' } }';
a runtime mediante una action nella response del tipo descritto in cui l’identificativo assoluto del campo viene ricavato
come composizione del parametro della request xform e del fieldId
<postActions>
<action name="xfocus(' 1_F0_WIN_Sample1a_SamplePanel_Form1_customerstatus ')"/>
</postActions>
Segnale acustico su errore in digitazione (beep)
Aggiunta la possibilita di emettere un suono in fase di errore di digitazione.
Selezionabile da menu “Impostazioni utente”
Close della window (xclose, xconfirmedClose)
Alla chiusura dei pannelli con sulla icona x in alto a destra viene invocato il metodo close se per la window è stata
definita la proprietà l'url.
Se non gestita o non prevista, il ServiceBus parte server risponde con la conferma della chiusura della window.
Standard nella definizione della proprietà style dei field
Per uniformità la definizione della proprietà style degli oggetti di tipo XFIELD da oggetto passa a stringa.
L’UIEngine supporterà le due modalita per garantire la compatibilità con le definizioni dei dizionari già realizzati:
come stringa (nuova) e come oggetto (vecchia modalità, deprecated).
Il Wizard leggerà la vecchia modalità e in fase di salvataggio la convertirà usando la nuova modalità.
diz["FLD_SampleA0"]='{"id":"CampoStyleStringa", "attrname":"CampoStyleStringa",
"style":"{\'background\':\'#FF0000\', \'color\':\'#FFFFFF\' }" , "labelStyle":"left" } ';
diz["FLD_SampleA1"]='{"id":"CampoStyleObj",
"attrname":"CampoStyleStringa",
"style":{"background":"#FFFF00", "color":"#FFFFFF"} , "labelStyle":"left" } ';
Window: Introdotto meccanismo per l’apertura sfalsata delle finestre
Si disporranno in modo sfalsato (20pixel piu in basso e più a destra della finestra precedente) fino a 4 livelli per poi
riprendere dall’alto.
Liste: UNION tra tabelle
Per realizzare l’UNION tra due tabelle è possibile usare nel file XML la direttiva UNIONTABLE=”nomeTabella”
ANRI200F.XML direttiva <union unionTable="ANRI200T" />)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
(es. in
Pagina 101 di 167
<?xml version="1.0" encoding="ISO-8859-1"?>
<querydefinition additionalOrderClause="" additionalWhereClause=""
name="ANRI200F"
description="Registri IVA"
table="ANRI200F"
resourceFile="conf\ApplicationResources"
pagingSize="20" maxSize="1000" >
<union unionTable="ANRI200T" />
<attribute…………………………………………………………………………………
…………………………………………………………………………………………………
Liste: Clausola DISTINCT nella SELECT.
La clausola DISTINCT serve a non ripetere nei risultati della SELECT quelli con lo stesso valore.
Per ottenere un query string del tipo :”SELECT DISTINCT …….” basta inserire nella definizione del dizionario il campo
“distinct”:”true”.
Per esempio:
diz['ACT_PFCLPRO']='{id:"PFCLPRO", type:"PF", file:"AAC0" , "show":["cdcli","rascl","loccl","procl"], "sort":"procl",
"distinct":"true"}';
Per default la distinct è false.
L’informazione relativa al distinct è inserita anche nella response nel parametro
_distinct=true(/false).
Menu contestuale: Richiamo di azioni ACGWebEdition o Express da flyingmenu su liste e menu contestuali
su campi
E’ possibile definire un’azione nel menu contestuale associata ad una lista o ad un campo che invochi un’azione di
ACGWebEdition o di ACGExpress.
Esempio:
Supponiamo di collegare il richiamo dell’Anagrafico clienti WebEdition al flyingmenu di una lista o su un menu attivo su
un campo
// definizione dell’azione
diz["CMD_ClientiWF"]="js:xACG(\'AAC0\',\'ACGV3\',\'!key\'
// da menu su campo
diz["MNU_RdPList"]=' [ "CMD_RdPCreate", "CMD_RdPUpdate", "CMD_ClientiWF" ] ';
// da menu tipo navigazione
diz["NAV_PFAAC0menu"]='PFBOTE|PFBOTE1|XCLGX05|PFCLPRO|ClientiWF';
Menu sulle liste modificabile/disattivabile dinamicamente
E’ possibile modificare dinamicamente la proprietà menu contestuale (flyingmenu sulle liste) da programma, inserendo
nella response una action con la seguente sintassi
xchangeMenu('<id assoluto del pannello>','<nuovo id menu>')
Es.
<postActions>
<action name="xchangeMenu('1_F0_WIN_MyWindow_MyList','4RdPMenù)"/>
</postActions>
La stessa funzione può essere usata per disattivare il menu impostando a stringa vuota l’id del menu.
<postActions>
<action name="xchangeMenu('1_F0_WIN_ MyWindow_MyList',’’)"/>
</postActions>
La nuova impostazione del menu è valida sulla lista indicata e rimane attiva anche nelle operazioni successive di reload,
nuova query utente,…
Le nuove impostazioni si perdono con la chiusura della finestra.
Per posizionare le label in modo che siano allineate con i campi input sottostanti
E’ possibile disegnare un pannello di questo tipo con la label indicata nel riquadro rosso allineata con i campi
sottostanti.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 102 di 167
Esempio:
La prima stringa è locale-dipendente, la seconda è cablata. Rimangono valide le possibilità di modificare dinamicamente
da server (vedi paragrafo relativo).
diz["FLD_WHSRaggrNumero"]=' {"id":"WHSRaggrNumero" , "type":"label", "value":"'+xLbl('ID')+'",
"labelStyle":"width:150px"}';
diz["FLD_WHSRaggrData"] =' {"id":"WHSRaggrData"
, "type":"label", "value":"WHSRaggrData",
"labelStyle":"width:60px"}';
"label":"",
"label":"",
Come effettuare dei controlli sui campi di un pannello
Su un pannello con 2 campi (A e B) si vuole attivare un controllo sul browser che verifichi (all'uscita dal campo B),
se il valore del campo B è maggiore del campo A, eventualmente emettendo un messaggio di errore sul campo B.
// xisGT è il codice da inserire in una libreria del proprio prodotto
// nel caso di funzioni generalizzate si provvederà a renderle disponibili nelle librerie di base
// prerequisito il campo A e B appartengono allo stesso Form/pannello
diz["LBL_IT_MSG_LTError"]="Valore minore del campo &1";
diz["LBL_EN_MSG_LTError"]="Valore less then field &1";
function xisGT(aId){
var aObj=$$(event.srcElement.formId+'_'+aId);
if (typeof(aObj)!='undefined'){
if((event.srcElement.value<=aObj.value)){
var aMsg0=xmsg('MSG_LTError',aId);
xaddMsg(event.srcElement.id,event.srcElement.winId,aMsg0)
}
}
}
diz["PNL_LaunchPanel"]='{ '
+' "id":"LaunchPanel", ...
+','+
' "fields":[ '+
$d2("FLD_SampleNum", " attrname:'A', row:1, col:0")
+','+
$d2("FLD_SampleNum", " onblur:\"xisGT('A')\", attrname:'B', row:2, col:0")
Campi: Disabilitazione formattazione numerica
E’ possibile disabilitare la formattazione dei numeri (separatori delle migliaia) impostando l'attributo thousands al
valore false nella proprietà dataformat del campo.
Esempio
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 103 di 167
diz["FLD_SampleNum26"]='{
"dataformat":"{thousands:false,places:2}","labelStyle":"width:300px;position:left",
"style":{"size":12,"maxlength":12}, …
© Copyright ACG Srl 2014 Tutti i diritti riservati.
"datatype":"DECIMAL",
Pagina 104 di 167
2.8 Tool di navigazione
Il tool di navigazione è accessibile tramite il menu Vision4, tramite la combinazione di tasti Ctrl +
click sulla voce di menu. La voce di menu selezionata deve essere un menu o una lista di tipo PF:
Si apre una window che carica le informazioni relative all’azione/menu selezionato.
Cliccando ad esempio su Lista Client, si aprirà la seguente finestra:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 105 di 167
Nella testata del pannello è possibile visualizzare:
 il contenuto del menù (PFAAC0menu) associato alla Lista Clienti
 l’id dell’azione selezionata
 i campi di input obbligatori per inserire il nome della nuova azione e il suo valore
 la lista dei file xml presenti nell’applicazione (e a cui il cliente corrente è abilitato)
Dalla lista dei file xml è possibile tramite menu contestuale scegliere “Nuova azione”. Questo
permette di creare un’azione sul menu della Lista clienti che punti al file xml selezionato (e quindi
alla lista corrispondente).
Al lancio dell’azione si apre una nuova window, dove vengono caricate le informazioni relative al file
xml selezionato. Supponiamo ad esempio di aver selezionato il file BOTE.xml.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 106 di 167
Nella parte centrale della window è presente la lista dei campi della tabella.
Con doppio click sulla riga è possibile andare a modificare le proprie preferenze sulla lista,
indipendentemente dalle impostazioni presenti nel file xml (key, show e sort):
E’ possibile inoltre selezionare più righe ed indicare tali righe come chiavi con il click sull’icona
chiave, e con la stessa modalità indicare le colonne visualizzate e i criteri di ordinamento
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 107 di 167
Cliccando sul tasto Edit del pannello Lista campi, vengono aggiornate le informazioni della nuova
action, visibili esplodendo il primo pannello Azione:
Supponiamo ad esempio di aver impostato 4 campi come campi chiave:
Tramite l’ultimo pannello è infine possibile aggiungere delle condizione di where aggiuntive:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 108 di 167
cliccando su Add, la condizione viene aggiunta ad una lista di condizioni:
A questo punto è possibile aggiungere altre condizioni in AND o in OR, o cancellare la condizione
creata. Per aggiungere tali condizioni alla nuova azione, è necessario cliccare sul bottone di edit del
pannello Condizioni di Where, che aggiornerà il campo Where del pannello di testata.
Per completare la creazione della nuova azione cliccare su Salva, in questo modo le informazioni
della nuova azione vengono riportate sulla prima finestra:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 109 di 167
A questo punto si può modificare la label dell’azione e completare con il salvataggio con il tasto
Salva. Il salvataggio ha come effetto la scrittura in un file con estensione js (legato all’utente), la
definizione della nuova azione e del menu aggiornato.
Per visualizzare le modifiche effettuate è necessario un refresh del browser.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 110 di 167
3. Componente Controller
3.1 Introduzione
In un’architettura che implementa il pattern MVC la componente Controller determina il modo
in cui l'applicazione risponde agli input dell'utente. Essa esamina le richieste dei client, estrae i
parametri della richiesta e li convalida, si interfaccia con lo strato di business logic dell'applicazione,
sceglie la successiva vista da fornire all'utente al termine dell'elaborazione.
In ACG Service Bus si è scelto di utilizzare la framework Struts versione 1.3.8 per
implementare questa componente, per via della maturità ed affidabilità raggiunte nel corso degli anni
(la prima versione risale al 2000 ed è tuttora supportata da una vasta e consolidata comunità di
programmatori), dell’ampia diffusione e conoscenza dell’open-source e per la flessibilità che ha
consentito di implementare una serie di comportamenti propri dell’architettura ACG.
Ulteriori informazioni sulla framework Struts possono essere reperite sul web, accedendo al
sito ufficiale sopra menzionato della Apache Software Foundation o consultando la vastissima
bibliografia pubblicata, consistente in articoli, tutorial e documentazione per i programmatori (si
leggano ad esempio gli articoli pubblicati sul sito IBM developerWorks, java.HTML.it o
ONJava.com); nel seguito verranno fornite una serie di indicazioni sulle modalità di utilizzo della
framework presupponendo una conoscenza adeguata della stessa.
In ACG Vision4si è scelto, come detto nell’overview architetturale, di non utilizzare Struts
con le sue tag-libraries per costruire le interfacce, avendo previsto la possibilità di definirle in modo
dichiarativo attraverso l’uso di un dizionario dati e di un engine in grado di costruire e popolare a runtime i pannelli sulla base delle definizioni previste nel dizionario stesso. Tutto ciò è stato reso
possibile grazie all’integrazione del template engine Velocity con Struts.
3.2 Integrazione Velocity – Struts in ACG Service Bus
Velocity è un motore di template basato su Java. Può essere usato come utilità indipendente
per generare codice sorgente, HTML, relazioni o può essere combinato con altri sistemi per fornire
servizi di template. Velocity è basato sul paradigma "Model View Controller", che rafforza la
separazione tra il codice Java e il template HTML.
L’utilizzo di Velocity nello sviluppo di applicazioni web consente la conduzione in parallelo
delle attività di disegno dell’interfaccia e codifica del codice servente da parte di web designer e
programmatori Java sulla base del pattern MVC, consentendo ai primi di focalizzarsi sulla creazione
di pagine web e dando la possibilità agli altri di concentrarsi sulla scrittura di codice che realizza la
logica di business e di controllo. Velocity costringe infatti gli sviluppatori a separare il codice Java
dalle pagine web, rendendo le applicazioni web più facilmente manutenibili e potendo costituire
un’alternativa alle Java Server Pages (JSPs) or PHP.
Le funzionalità di Velocity possono essere ulteriormente arricchite dalla creazione di custom
tools. Un tool è semplicemente una classe java che può eseguire vari task quando viene resa
disponibile al motore di Velocity.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 111 di 167
VelocityTools è un insieme di sottoprogetti di Velocity con il comune obiettivo di creare tool
ed una infrastruttura per creare applicazioni web e non, utilizzando il “Velocity template engine”.
Il sottoprogetto VelocityStruts integra Velocity con la framework Apache Struts consentendo
l’uso dei template Velocity congiuntamente o in alternativa alle pagine JSP nell’implementazione
della parte View di un’applicazione web.
Diverse alter framework offrono un supporto nativo ai Velocity templates; questo progetto
fornisce lo stretto necessario per fornire agli sviluppatori Struts un’alternativa alle JSP.
Osservando il flusso elaboravo tipico di un’applicazione web nella figura precedente, si può
osservare come l’aggiunta di Velocity non ne modifichi in maniera sostanziale la logica. La libreria
java velocity-struts.jar introduce una servlet di Velocity stand-alone che elabora i template file (nello
specifico, il jar file è velocity-tools-x.x.jar) ed usa una serie di tool predefiniti per fornire un accesso
trasparente ad oggetti tipici di Struts (ad esempio. message resources, form beans, errors, links). Il
file di mapping delle azioni conterrà semplicemente un ActionForwards che indirizza opportunamente
il controllo delle view basate su Velocity invece di indirizzarle ad una JSP.
Si noti che le tecnologie Velocity e JSP non sono mutuamente esclusive: entrambe le
tecnologie possono essere usate nella stessa applicazione senza alcun problema. Questo consente agli
sviluppatori di utilizzare l’opzione Velocity senza modificare pesantemente un’applicazione Struts.
3.2.1 Benefici
Ci sono diversi motivi per utilizzare Velocity come tecnologia per la realizzazione dello strato
View di un’applicazione web. Qui di seguito ne sono riportati alcuni:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 112 di 167








Velocity aiuta a realizzare una chiara separazione tra lo strato view e quello model/control.
Ciò determina una netta separazione tra il disegno applicativo e la presentation, tra i Designers
dell’interfaccia e gli sviluppatori back-end
Velocity Template Language (VTL) ha poche direttive, è semplice e facile da imparare.
Velocity si può estendere facilmente con i Tools che sono semplicemente delle classi con
metodi pubblici. Tipicamente tali classi sono più semplici e facili da sviluppare rispetto al JSP
custom tag libraries.
usando il TilesTool è possibile effettuare un mix di Velocity e JSP tiles nella stessa pagina,
consentendo una migrazione graduale da una tecnologia all’altra.
le Velocity macros rappresentano uno strumento molto potente per i View Designer,
consentendo la creazione di prototipi riutilizzabili o eliminando la necessità di sviluppare una
custom tag library o altri tool server-side
i template di Velocity NON sono limitati all’HTML e possono essere usati per qualsiasi tipo di
output testuale, quale può essere un file XML, SQL, ASCII, PostScript, etc.
Velocity, che realizza il caching dei template, consente il raggiungimento di livelli di
performance uguali o superiori a quelli di una JSP
Velocity è supportata da una comunità attiva di sviluppatori ed utenti.
Alcune referenze:
http://www-128.ibm.com/developerworks/java/library/j-sr1.html
http://www-128.ibm.com/developerworks/java/library/j-velocity/
http://jakarta.apache.org/velocity/
http://jakarta.apache.org/velocity/tools/struts/
Nell’architettura ACG Vision4 è stato adottato Velocity con il sottoprogetto di integrazione
con Struts allo scopo di demandare al template engine formattazione dei dati contenuti nei form bean
in un file XML con struttura “interpretabile” dall’UI engine che costruisce l’interfaccia utente.
Nello specifico, l’invocazione di una action Struts termina con un forward ad una pagina di velocity
(vale a dire un file con estensione .vm) che, tramite i tool del sottoprogetto Velocity-Struts
(FormTool, ErrorTool, EscapeTool, StrutsLinkTool), è in grado di leggere il contenuto del form bean
associato all’action e produce una risposta in formato XML interpretabile dall’UI Engine.
Il formato tipico di una risposta XML è il seguente
<?xml version="1.0" ?>
<response xwin="5_F1_WIN_RdP"
xform="5_F1_WIN_RdP_PanelInPanel_Form1"
xfield="" xmethod="save" xexec="" xcontext="2" >
<preActions>
</preActions>
<postActions>
<action name=” xreload(‘Rows_list’)“/>
</postActions>
<data>
<item name="CDCSO" value="001700"
© Copyright ACG Srl 2014 Tutti i diritti riservati.
></item>
Pagina 113 di 167
<item name="FLIMO" value="D" ></item>
<item name="DTREO" value="20073030" ></item>
<item name="datas" value="" ></item>
<item name="NRCTO" value="14
" visibility=”false”></item>
<item name="xcontext" value="2" mandatory=”true” ></item>
<item name="numberOfElements" value="0" ></item>
<item name="CDCSO_rascl" value="A &amp; A SPA" ></item>
<item name="NRIMO" value="14" disabled=”true” ></item>
<item name="currentPage" value="1" ></item>
</data>
<msgs>
<msg tgt=”DTREO”>Data non valida</msg>
</msgs>
</response>
In tale documento XML è possibile riconoscere i seguenti elementi:
-
l’intestazione <response> contenente informazioni sulla finestra cui è destinata, il metodo
dell’action di Struts che ha prodotto la risposta, il campo cui si riferisce (opzionale), il contesto
applicativo (si veda quanto riportato nel paragrafo “ACGDynaActionForm a proposito della
property denominata xcontext)
-
la sezione <data> che include un insieme di elementi (<item>) contenenti i nomi degli property
del form bean, i relativi valori ed (opzionalmente) le informazioni visuali (visibility, disabled,
mandatory e display)
-
la sezione <postActions> che include un insieme di elementi (<action>) contenenti i nomi di
operazioni da eseguire sul client ad opera dell’UI engine dopo aver riempito la finestra con i dati
-
la sezione <preActions> che include un insieme di elementi (<action>) contenenti i nomi di
operazioni da eseguire sul client ad opera dell’UI engine prima di riempire la finestra con i dati
-
la sezione <msgs> che include un insieme di elementi (<msg>) contenenti i messaggi da
visualizzare nella finestra, con l’indicazione opzionale del target (vale a dire del campo nella
finestra cui si riferisce il messaggio)
Le pagine di Velocity di utilizzo comune sono presenti nel percorso <context_root>\pages e
sono denominati:
- output.vm: usato per formattare la risposta di un metodo Struts invocato tipicamente dopo aver
eseguito un’operazione che interessa l’oggetto di business nella suo complesso (ad esempio nel
caso di immissione o modifica di un record sul DB)
- check.vm: usato per formattare la risposta di un metodo Struts che tipicamente comporta la
modifica di un numero limitato di attributi del form bean e una modifica “limitata” dell’interfaccia
(ad esempio nel caso di invocazione di un metodo di decodifica all’uscita campo)
- headerRows.vm: usato per formattare la risposta di un metodo Struts che realizza la gestione
delle righe in un oggetto di business del tipo testata-righe
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 114 di 167
3.3 Action e Form Bean in ACG Service Bus
Benché nel modello di sviluppo ACG Vision4sia possibile usare qualsiasi tipo di Form e di
Action previsti dalla framework Struts, si è ritenuto opportuno selezionare tipi specifici allo scopo di
semplificare il processo di sviluppo, standardizzando e generalizzando taluni comportamenti tipici
dell’architettura ACG.
3.3.1 ACGDynaActionForm
Nel modello di sviluppo ACG Vision4si è scelto di utilizzare le form dinamiche della
framework Struts, vale a dire le istanze della classe org.apache.struts.action.DynaActionForm (si
veda il seguente link per reperire ulteriori informazioni) al fine di rendere più agevole lo sviluppo
delle applicazioni: creare e mantenere una classe concreata di tipo ActionForm per ogni oggetto di
business, con la dichiarazione esplicita dei suoi attributi ed i relativi metodi set() e get(), è un’attività
dispendiosa, oltre che noiosa.
Nel file di configurazione di Struts della web application di ACG Vision4è stato definito in
particolare un form bean di uso comune denominato ACGDynaActionForm dal quale sono stati fatti
derivare i form bean specifici delle varie action, mediante la clausola extends nella dichiarazione degli
stessi (si veda ad es. la dichiarazione del form bean DynaRdpForm).
<form-bean name="ACGDynaActionForm"
type="org.apache.struts.action.DynaActionForm">
<form-property name="xcontext" type="java.lang.String" />
<form-property name="xexec" type="java.lang.String" />
</form-bean>
<form-bean name="DynaRdPForm" extends="ACGDynaActionForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="DTREO" type="java.lang.String" />
<form-property name="NRCTO" type="java.lang.String" />
<form-property name="NRIMO" type="java.lang.String" />
<form-property name="CDCSO" type="java.lang.String" />
<form-property name="FLIMO" type="java.lang.String" />
<form-property name="CDCSO_rascl" type="java.lang.String"/>
</form-bean>
ACGDynaActionForm potrà essere suscettibile dell’aggiunta di ulteriori proprietà supportate
dall’architettura, che potranno essere automaticamente estese a tutti i form bean che da esso derivano.
In particolare il form bean ACGDynaActionForm contiene la property xcontext che definisce
l’operazione in corso sull’oggetto di business (immissione, modifica, etc.) ed è in grado di innescare
comportamenti visuali specifici in fase di presentazione dei dati.
I valori attualmente gestiti sono:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 115 di 167
0
Non definito
1
Immissione oggetto di business
2
Modifica oggetto di business
5
Visualizzazione
Al fine di sfruttare il supporto alla validation che Struts fornisce, grazie al quale è possibile
effettuare in modo automatico e dichiarativo i controlli formali sui parametri passati alle Action, nel
modello di sviluppo ACG Vision4si è scelto di specificare per i form bean il tipo
org.apache.struts.validator.DynaValidatorForm, che fonde le caratteristiche di dinamicità e di
validazione dichiarativa sopra menzionate.
3.3.2 ACGDispatchAction
Per quanto riguarda la dichiarazione delle classi Action, nel modello di sviluppo ACG
Vision4si è scelto di estendere la classe standard org.apache.struts.actions.DispatchAction (si veda il
seguente articolo alla pagina http://www.mokabyte.it/2004/09/jstruts-8.htm che ne descrive l’utilizzo
nella framework Struts), creando la classe com.ibm.acgv4.guiweb.ACGDispatchAction dalla quale
sono state fatte derivare le action che realizzano le diverse funzioni applicative. L’uso della
DispatchAction di Struts consente, in generale, un’implementazione di tipo dichiarativo e permette di
compattare più funzionalità in un’unica classe java, mentre la classe ACGDispatchAction permette di
implementare metodi e funzionalità di utilizzo comune alle varie Action in architettura ACG Vision4.
Viene riportata qui di seguito una dichiarazione tipica di una Action in ACG Service Bus:
<action path="/RdPAction" type="com.ibm.acgv4.action.RdPAction"
name="DynaRdPForm" scope="request" validate="false"
input="/pages/output.vm" parameter="xmethod">
<set-property key="actionId" value="RDP"/>
</action>
essendo, nel caso in oggetto, com.ibm.acgv4.action.RdPAction
com.ibm.acgv4.guiweb.ACGDispatchAction.
una
sottoclasse
di
Nella dichiarazione delle Action il parametro “parameter” deve essere sempre impostato
al valore xmethod per consentirne il corretto funzionamento in architettura ACG Vision4.
Nella definizione di un’Action deve essere specificata la property “actionId” indicando un
prefisso che viene utilizzato dall’architettura ACG Vision4per recuperare, insieme al parametro
xmethod, l’identificativo dell’operazione cui è associata l’operazione. Ad esempio, nel caso di
richiamo dell’action specificando l’URL
http://servername/context-root/RdpAction.do?xmethod=approve
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 116 di 167
verrà ricercata l’operazione RDP_approve nel file delle operazioni KOPER00F, controllata
l’autorizzazione all’esecuzione dell’operazione ed effettuato il logging con i dati relativi (si vedano i
capitoli relativi ai due argomenti menzionati).
In generale, nella dichiarazione dell’action è opportuno specificare nel parametro “validate” il
valore false e richiedere la validazione di Struts solo nei metodi per i quali è richiesta la validazione
del form bean, mediante scrittura della seguente linea di codice:
ActionMessages errors = actionForm.validate(mapping, request);
Ciò eviterà che venga attivata la validazione del form bean anche nel caso di invocazione di
metodi che devono effettuare operazioni puntuali su di esso (ad esempio decodifica di dati), senza che
siano impostate tutte le sue proprietà.
Il parametro “scope”, in generale, dovrà essere impostato al valore request, consentendo così
l’attivazione simultanea di più finestre nello stesso desktop relative alla medesima funzionalità
(nell’esempio sarà possibile aprire nello stesso desktop due finestre per l’immissione di una Richiesta
di Preventivo, essendo RdPAction la classe Action per la gestione dei preventivi ACG).
ACG Service Bus è in grado di conservare lo stato di un Form bean nella sessione di lavoro,
grazie all’utilizzo di un command specifico che è in grado di “fondere” i dati passati al form bean in
una request con quelli impostati nelle request precedenti.
Per garantire questo automatismo, è necessario che il programmatore, prima della uscita da un
metodo che ha modificato lo stato di un form bean, inserisca la seguente linea di codice:
putActionFormInSession(request, actionForm, mapping);
essendo:
request = parametro di tipo HTTPServletRequest in input al metodo
actionForm = il cast a DynaValidatorForm del parametro di tipo ActionForm in input al metodo
mapping = parametro di tipo ActionMapping in input al metodo
Il metodo putActionFormInSession, ereditato da ACGDispatchAction, salva il form bean nella
sessione http come attributo con chiave ottenuta dalla concatenazione dell’identificativo della frame
(vedi documentazione della User Interface) e del nome del form bean.Ad esempio la chiave può
assumere il valore 1_F0_WIN_Rdp_DynaRdpForm, essendo:
-
1_F0_Win_RdP l’identificativo univoco della frame nel desktop
DynaRdpForm il nome del form bean.
Il nome della chiave può essere ottenuto dal metodo
getKey(HTTPSerVletRequest request, String key_suffix)
essendo key_suffix nello specifico il nome del form bean.
Il mapping delle Action in ACG Service Bus tipicamente prevede l’impostazione del
parametro “input” al valore pages/output.vm, che rappresenta la pagina di default verso la quale viene
reindirizzata la risposta per essere formattata nel formato XML richiesto dalla User Interface.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 117 di 167
3.3.3 Global forwards
Un metodo di un’azione Struts in ACG Service Bus tipicamente prevede un forward, tramite
scrittura dell’istruzione return mapping.findForward(“ . . . ”), alle seguenti risorse:
output: nel caso in cui si voglia aggiornare in modo “integrale” il pannello che ha invocato
l’azione (la risposta viene inviata alla pagina output.vm precedentemente descritta nel paragrafo che
descrive l’integrazione della framework Struts con il template engine Velocity)
- check: nel caso in cui si voglia aggiornare in modo “puntuale” il pannello (ad esempio
invocazione di un metodo di decodifica all’evento “uscita-campo”); la risposta, in questo caso,
viene inviata alla pagina check.vm
- headerRows: nel caso in cui si debba aggiornare un pannello contenente il componente grafico
che rappresenta le righe di un business object che viene rappresentato nella forma testa-righe (la
risposta viene inviata alla pagina headerRows.vm)
-
I tre forward sopra specificati rappresentano sono stati specificati come global forwards nei
file di configurazione di Struts.
3.3.4 Alcuni metodi di ACGDispatchAction
Nella classe ACGDispatchAction sono stati implementati alcuni metodi di comune utilizzo
nelle action che da essa derivano; qui di seguito se ne menzionano alcuni:
-
getLogon(HttpServletRequest request, HttpServletResponse response): restituisce l’istanza della
classe com.ibm.acgv4.base.ACGLogon con le informazioni collegamento al sistema
-
getHibernateSession(ACGLogon logon, HttpServletRequest request, HttpServletResponse
response): restituisce un’istanza della Session di Hibernate necessaria all’esecuzione di una
transazione Hibernate in un metodo dell’action
-
decode(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response): effettua la decodifica di un attributo del form bean eseguendo il
metodo checkId() di una classe Home di Hibernate o uno statement SQL (specificato nel file
decode.properties presente in <context_root>/WEB-INF/classes/conf). Richiede l’implementazione
del metodo getResource(String propName) nella classe Action concreta, che deve resituire per ogni
property del form bean che deve essere decodificata:

la chiave nel file WEB-INF\classes\decode.properties dello statement SQL che deve essere
eseguito (il nome della chiave coincide con il nome della tabella su cui deve essere eseguita
la query

il nome qualificato della classe Home che deve implementare il metodo checkId(String id,
BaseException be) che recupera il contenuto del campo descrizione del record individuato
dall’id passato (nel caso di record non trovato restituisce null ed imposta il messaggio
d’errore nell’oggetto di tipo BaseException passato)
-
saveACGV4Errors(HttpServletRequest request, ActionMessages errors): da usarsi in luogo del
metodo standard di Struts saveErrors(HttpServletRequest request, ActionMessages errors)
-
putObjInSession(HttpServletRequest request, Object obj, String key_suffix) e
getObjFromSession(HttpServletRequest request, String key_suffix): vengono usati per salvare un
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 118 di 167
oggetto nella sessione http e per recuperarlo, usando un suffisso per l’identificazione dell’oggetto
(come nel caso del metodo putActionFormInSession la chiave viene ottenuta dalla composizione
dell’identificativo della finestra nel desktop con il prefisso passato)
-
removeObjFromSession(HttpServletRequest request): rimuove tutti gli oggetti salvati nella
sessone http dall’Action
-
close(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response): viene richiamato alla chiusura di una finestra ed esegue la
rimozione di tutti gli oggetti salvati nella sessione http dall’Action richiamando il metodo
removeObjFromSession
3.4 Chain of Responsibility
Nel modello di sviluppo ACG Vision4la catena dei command della framework Struts che
elaborano una invocazione di una Action è stata integrata, sfruttando le caratteristiche di
configurabilità offerte dall’open-source, con il richiamo di tre command dichiarati nel file di
configurazione acgv4-chain-config.xml e referenziati nel file chain-config.xml, presenti nella
cartella WEB-INF nella applicazione web,.
I command sono classi presenti nel package com.ibm.acgv4.base.chain.commands che
estendono la classe org.apache.struts.chain.commands.ActionCommandBase ed implementano il
metodo execute(ActionContext actionCtx).
Nello specifico i command sono:
-
AuthorizationCommand: esegue il controllo di autorizzazione all’esecuzione di un metodo di
una Action tramite la classe AuthorizationManager, che verifica l’autorizzazione dell’utente
all’esecuzione dell’operazione identificata dalla concatenazione della property “actionId” specificata
sulla Action con il metodo
-
MonitorCommand: traccia l’esecuzione di un metodo di una Action nel file di log delle azioni
del Modulo Base ACG (KFLOG00F) recuperando il codice dell’operazione associata
all’invocazione del metodo come specificato nel caso precedente
-
PopulateCommand: è deputato a popolare il form bean da inviare all’Action di Struts,
recuperando i dati presenti nella request http ed integrandoli con quelli salvati nella session dalla
Action (si legga quanto scritto in merito al metodo putActionFormInSession nel paragrafo
“ACGDispatchAction”)
-
CheckExitCommand: ha il compito di rilevare le exit automatiche e non associate all’operazione
lanciata
-
ExecuteExitCommand: ha il compito di eseguire le exit automatiche associate all’operazione
lanciata
-
OperationsConflictsMgmtCmd: ha il compito di creare i vincoli sulle risorse virtuali associate
all’opeazione lanciata
3.5 Configurazione in moduli
Si è sfruttata la possibilità propria di Struts di suddividere in moduli l’applicazione web,
creando una corrispondenza biunivoca tra i moduli applicativi ACG e non che si innestano
nell’applicazione web ed i moduli struts.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 119 di 167
Il file di configurazione principale struts-config.xml è riservato al Service Bus di ACG
Vision4, mentre per gli altri moduli si è convenuto di referenziare il file di configurazione di un
prodotto come struts-xx.xml, essendo xx l’acronimo abbreviato di un prodotto ACG (ad esempio
struts-ca.xml nel caso di Contabilità Aziendale, struts-te.xml nel caso di Tesoreria, etc.).
I file di risorse dei messaggi ApplicationResources.properties sono stati posizionati in:
-
WEB-INF\classes\conf nel caso del Service Bus
WEB-INF\classes\conf\xx nel caso degli altri moduli, essendo xx, come detto precedentemente,
l’acronimo abbreviato di un prodotto ACG
3.6 ACGValidator
Come noto la framework Struts fornisce gli strumenti per effettuare in modo automatico e
dichiarativo i controlli formali sui campi digitati in un form HTML.
In particolare, usando il Validator non è necessario scrivere alcun codice di validazione nel
metodo validate() degli ActionForm, ma è il Validator stesso che fornisce questa funzione purchè i
form bean dell'applicazione estendano uno degli ActionForm del Validator stesso: è questo il motivo
per il quale si è scelto di utilizzare la classe DynaValidatoForm come tipo d’elezione in ACG Service
Bus.
.
Il Validator è costituito da un insieme di classi predisposte per eseguire tutti i più comuni
controlli di validazione in genere usati nelle applicazioni, ma.esiste anche la possibilità di
creare routine di validazione non fornite dal Validator.
Il Validator inoltre supporta sia la validazione server-side che quella client-side mediante
opportune funzioni JavaScript, cosa non fornita dal meccanismo standard degli ActionForm di Struts.
La configurazione delle routine di validazione da applicare ad un campo di un form è fatta
mediante un file di configurazione XML, quindi esternamente all'applicazione ed è facilmente
modificabile al mutare delle esigenze applicative. Nel file validator-rules.xml vengono dichiarate tutte
le routine di validazione disponibili, i loro nomi logici e il codice JavaScript corrispondente a
ciascuna routine di validazione per l'esecuzione dei controlli client-side.
Nel file validation.xml si specifica come queste routine vengano applicate ai vari campi di
input dei form dell'applicazione, ai quali si fa riferimento mediante i nomi dei form bean dichiarati
nello struts-config.xml.
In ACG Service Bus è stata creata una classe di validazione, denominata ACGValidator e
presente nel package com.ibm.acgv4.guiweb, tramite la quale è possibile gestire alcune validazioni
proprie del mondo ACG dichiarate nel file di configurazione acg-validator-rules.xml.
Nel file validation.xml presente nel sottopercorso WEB-INF è possibile, ad esempio, verificare
l’uso della regola acgDate che esegue la validazione delle date, nelle due opzioni che consentono di
considerare la data 9999999 una data valida (vedi validazione della property SCAFI) o viceversa non
viene considerata ammissibile una data nel formato precedente (vedi validazione della property
DTREO).
I file validation.xml sono stati posizionati in:
-
WEB-INF nel caso del Service Bus
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 120 di 167
-
WEB-INF\classes\conf\xx nel caso degli altri moduli
3.7 Messaggi applicativi
Le classi java che rappresentano oggetti di business in genere contengono metodi atti a
validare i dati (attributi) dell’oggetto prima che essi vengano resi persistenti sul database. ACG
Service Bus mette a disposizione l’infrastruttura necessaria per creare un eccezione java che
rappresenti uno più errori applicativi(messaggi), decodificare la descrizione dell’errore secondo la
lingua dell’utente, spedire l’errore alla parte view.
3.7.1 La classe BaseException
In ACG Vision4è stata definita la classe BaseException che rappresenta una eccezione applicativa
(legata ad un testo di messaggio)
Occorre all’interno delle classi java creare un’istanza di tale classe specificando:

il path relativo che contiene il file dei messaggi ad eccezione della directory resources: ad
esempio “com.ibm.acgv4.ca”; se non specificato si assume quello base (com.ibm.acgv4.base”)

l’identificativo del messaggio: ad esempio “CA0002”

i parametri eventuali del messaggio ( esistono costruttori fino a quattro parametri)

eventualmente l’identificativo del campo visuale a cui l’errore si riferisce
Ad esempio:
BaseException be = new BaseException(“com.ibm.acgv4.ca”,”CA0002”,”NUMOV”);
throw be;
Da notare che la classe BaseException contiene il metodo addException(BaseException b1) per
poter annidare gli errori (messaggi) applicativi: ciò è utile nei metodi di validazione che riguardano
più campi o attributi e si vuole produrre una lista di messaggi applicativi.
3.7.2 Catalogo messaggi
Per ogni modulo applicativo occorre definire il file dei messaggi Messages.properties nella
directory relativa /com/ibm/acgv4/xx/resources dove xx è l’acronimo del modulo ACG.
Esempio: per la contabilità occorre creare il file Messages.properties nella directory
/com/ibm/acgv4/ca/resources
Esempio di contenuto del file:
##################################################
# {0} = $Token
CA0001=CA0001: Registrazione contabile {0} non corretta
##################################################
CA0002=CA0002: Specificare la riga avere
##################################################
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 121 di 167
3.7.3 Gestione dei messaggi in struts
ACG Vision4fornisce la classe BaseexceptionHandler in grado di catturare i messaggi
applicativi, decodificarli ed inviarli alla parte VIEW in formato xml.
Per fare ciò ogni modulo deve dichiarare nel file di configurazione di struts relativo al modulo
l’utilizzo della classe nel seguente modo:
<!-- Global Exceptions -->
<global-exceptions>
<exception key="errors.exception" scope="request"
handler="com.ibm.acgv4.guiweb.BaseExceptionHandler"
type="java.lang.Exception" />
</global-exceptions>
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 122 di 167
4. Componente Model
4.1 Introduzione
Il cuore dell'applicazione viene implementato dalla componente Model, che incapsulando lo stato
dell'applicazione definisce i dati e le operazioni che possono essere eseguite su questi. Quindi
definisce le regole di business per l'interazione con i dati, esponendo alle componenti View e
Controller rispettivamente le funzionalità per l'accesso e l'aggiornamento. Per lo sviluppo del Model
quindi è vivamente consigliato utilizzare le tipiche tecniche di progettazione object-oriented al fine di
ottenere un componente software che astragga al meglio concetti importati dal mondo reale. Il Model
può inoltre avere la responsabilità di notificare ai componenti della View eventuali aggiornamenti
verificatisi in seguito a richieste del Controller, al fine di permettere alle View di presentare agli occhi
degli utenti dati sempre aggiornati.
Nel modello di sviluppo ACG Vision4la Componente Model è stata implementata secondo due
modalità differenti, che possono essere adottate a seconda delle necessità e delle condizioni
progettuali, che possono essere sintetizzate rappresentate da vari fattori quali:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 123 di 167
-
competenze Java
disponibilità di codice legacy riusabile
necessità di re-ingegnizzare i processi
tempi di sviluppo
In dipendenza dalla possibilità/necessità di sviluppare codice “nuovo” Java o di riusare il codice
legacy (programmi RPG e similari) è possibile adottare una delle due opzioni di sviluppo della parte
Model:
- sviluppo “pure-Java” mediante utilizzo della framework open-source Hibernate per accedere
al database
- riutilizzo del codice legacy mediante utilizzo della Componente ACG Service Bus
denominata “Legacy Connector”
Nel seguito verranno descritti la framework Hibernate e l’uso che si è fatto della stessa in ACG
Service Bus, nonché la componente che consente il riuso dei programmi legacy, ferma restando la
possibilità di utilizzare un approccio misto avendo la possibilità di sviluppare codice Java ex-novo e
riutilizzare codice legacy.
4.2 Utilizzo della framework Hibernate in ACG Service Bus
Lo strato di persistenza maggiormente diffuso (soprattutto in applicazioni “Enterprise”) è
costituito da database ed in particolar modo da database relazionali. Imbattendosi in un’applicazione
del genere ci si rende presto conto che esiste una stretta relazione tra classi e tabelle del DB, tra
oggetti e “righe” delle tabelle e tra proprietà di oggetti costituite da altri oggetti dell’ applicativo e
relazioni (uno-uno, uno-molti, molti-molti) tra le varie entità del DB.
A questo punto ci si trova di fronte ad una scelta: scrivere “a mano” il codice SQL che ci serve
per creare (INSERT ....), modificare (UPDATE ...) e recuperare (SELECT) gli oggetti il cui stato è
memorizzato nel database oppure affidare questo compito (alla lunga ripetitivo) ad un “motore” di
bridging: uno strato software che si interpone tra l'applicativo e il database il quale, opportunamente
configurato, mantiene sincronizzato, con il DB sottostante e a prescindere dal tipo di DB, lo stato
degli oggetti persistiti in modo trasparente allo sviluppatore.
Esistono diversi software in grado di svolgere il compito descritto (Castor, OJB, ecc.) ma tra
tutti quello che più ha avuto fortuna e diffusione è Hibernate.
Hibernate permette un approccio alla persistenza completamente diverso da quello
tradizionale, un approccio totalmente orientato agli oggetti e trasparente allo sviluppatore.
Il meccanismo di bridging è alla base dei motori di persistenza CMP (Container Managed
Persistence) degli application server; vi è però una sostanziale differenza: le entità in un sistema j2ee
sono modellate da EJB di tipo entità e devono implementare interfacce o essere sottoclassi dello
standard enteprise; per essere usata con Hibernate, invece, una classe deve essere un POJO (Plain Old
Java Object) ovvero un semplice Java Bean costituito dalle proprietà e i rispettivi getters/setter
(quando serve).
Partendo da un database legacy Hibernate è in grado di mappare le tabelle in classi: ogni riga
della tabella sarà un'istanza della classe corrispondente. Lo sviluppatore non dovrà più occuparsi di
interagire con il DBMS per mezzo di JDBC, ma userà la più familiare forma degli oggetti e le comuni
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 124 di 167
strutture dati del linguaggio. Nonostante l'indubbio vantaggio di usare oggetti anziché statement SQL
inviati tramite JDBC e l'onere di gestire istanze di ResultSet, non ci troviamo di fronte ad un modello
Object Oriented, bensì ad un modello relazionale in cui le tabelle appaiono in forma di oggetti: per
lavorare con un modello realmente ad oggetti è sempre necessario introdurre un ulteriore strato di
traduzione tra oggetti-tabella e oggetti-modello, con un costo sia in termini di tempo che in termini di
codice da mantenere.
Nel seguito del paragrafo non si intende fornire una descrizione della framework, che può
essere recuperata consultando la documentazione in linea ai siti:
- Hibernate Official Site
- Reference guide
4.2.1
Session Factory e Configurazione
Per poter usare Hibernate è necessario realizzare una classe che implementi l'interfaccia
SessionFactory definita nella distribuzione standard; questa classe serve per creare nuove sessioni “di
lavoro” tramite le quali è possibile manipolare gli oggetti persistenti. Il SessionFactory per poter
essere usato necessita di essere preventivamente configurata per via programmatica oppure tramite un
file di configurazione.
Il file di configurazione (hibernate.cfg.xml) presente in <context>\WEB-INF\classes, si
presenta come segue:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.datasource">java:comp/env/jdbc_ds
</property>
<property name="hibernate.dialect">org.hibernate.dialect.DB2400Dialect
</property>
<!-- JDBC connection pool (use the built-in) -->
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider
</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>
</session-factory>
</hibernate-configuration>
Nel file di configurazione di Hibernate sono specificate, usualmente, righe del tipo:
<!-- Mapping files -->
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 125 di 167
<mapping resource="Ancl200f.hbm.xml"/>
<mapping resource="Anco200f.hbm.xml"/>
Una dichiarazione esplicita dei file di mapping non è possibile nella soluzione ACG, in quanto
lo schema (vale a dire la libreria sui sistemi iSeries) nel quale risiede una tabella dipende dal Sistema
Informativo al quale si collega l’utente.
Ciò implica che:
- la configurazione viene automaticamente creata al logon, recuperando tutti i file con estensione
hbm.xml presenti nella cartella <context>\WEB-INF\classes
- i file con estensione .hbm.xml si presentano come segue:
<?xml version="1.0"?>
<!DOCTYPE
hibernate-mapping
PUBLIC
"-//Hibernate/Hibernate
Mapping
3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ibm.acgv4.Ancl200f" table="ANCL200F" schema="ACG_SCHEMA">
<comment>Anagrafico clienti</comment>
<id name="cdcli" type="string">
<column name="CDCLI" length="6" />
<generator class="assigned" />
</id>
DTD
La particolarità del file di mapping delle tabelle ACG risiede nel fatto che nell’attributo
dell’elemento <class> deve essere specificata la parola chiave ACG_SCHEMA
schema
- in fase di creazione della configurazione di un sistema informativo, la costante ACG_SCHEMA viene
sostituita con il nome effettivo della libreria nella quale risiede la tabella in quel sistema
informativo
- esisteranno, nella cache dell’applicazione web, tante configurazioni, create dinaminacamente
all’atto del primo collegamento, quanti sono i Sistemi Informativi ai quali si sono collegati gli
utenti.
- il meccanismo è completamente trasparente al programmatore ed è realizzato dalla classe
com.ibm.acgv4.base.HibernateSessionFactory presente nella libreria acg_base.jar
Viene riportato qui di seguito l’utilizzo di Hibernate in un’Action Struts (si veda anche quanto
riportato nel paragrafo Controller Component).
Transaction tx = null;
Session session = null;
try {
ACGLogon logon = getLogon(request, response);
com.ibm.acgv4.model.Rrct300f element =
(com.ibm.acgv4.model.Rrct300f) getObjFromSession(request, RRCT300F);
if (element == null) element = new Rrct300f();
//Impostazione proprerty del POJO
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 126 di 167
element.setNrimo(getInt(actionForm, "NRIMO"));
element.setDtreo(getInt(actionForm, "DTREO"));
element.setNrcto((String) actionForm.get("NRCTO"));
element.setCdcso((String) actionForm.get("CDCSO"));
element.setFlimo(getChar(actionForm, "FLIMO"));
element.setDtv20(logon.getCurrentCompany());
element.setNuv20(logon.getUser());
session = getHibernateSession(logon, request, response);
tx = session.beginTransaction();
setContext(actionForm, "2");
session.saveOrUpdate(element);
tx.commit();
putObjInSession(request, element, RRCT300F_SUFFIX );
} catch (Exception e) {
if (tx != null && tx.isActive()) tx.rollback();
throw e;
} finally {
putActionFormInSession(request, actionForm, mapping);
session.close();
}
Le operazioni necessarie per eseguire una transazione consistono in:
- recupero dell’istanza di logon al sistema
- recupero dell’istanza (se esiste) del POJO rappresentante l’oggetto di business dalla sessione http;
nel caso in cui non esiste, viene istanziato tramite il costruttore di default
- impostazione delle proprietà del POJO, recuperando i valori dal form bean
- recupero dell’istanza della Session Hibernate
- inizio della transazione Hibernate
- salvataggio dell’oggetto sul DB tramite invocazione del metodo saveOrUpdate() sulla session,
passando l’oggetto POJO. Hibernate automaticamente mappa il bean sulla tabella di database,
utilizzando il file di mapping associato alla classe
- salvataggio del POJO nella sessione http per futuro utilizzo
- commit della transazione
- chiusura della session
4.3 Legacy Connector
ACG Service Bus consente, tramite questo componente, il riutilizzo di codice legacy ACG da
parte di applicazioni client, sia attraverso le tecnologie J2EE che attraverso le tecnologia standard dei
web service. Nel presente documento, con l’espressione “codice legacy ACG” ci si riferisce a:

qualsiasi programma RPG, RPG-ILE e CLP che gira su un server iSeries sotto architettura di
Modulo Base, che riceva in input quale unico parametro la KPJBA;
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 127 di 167

qualsiasi classe java ottenuta dalla conversione, effettuata tramite i tool Caravel e Interactive
Converter, di un programma RPG, RPG-ILE e CLP che soddisfi le condizioni descritte nel punto
precedente.
Si ipotizza che il riuso del codice legacy possa prevedere una sua modifica per:

aderire al programming model definito dall’architettura ACG Vision4relativamente alla
componente di riuso

estrapolare la logica di presentazione da quella di business o condizionare il flusso elaborativo in
modo da non escludere/inibire l’interazione con l’utente tramite l’emissione di interfacce video

prevedere una nuova modalità di ricezione di dati in input e di emissione in output, in
considerazione del fatto che il codice legacy non deve essere più visto come software destinato a
produrre dati da presentare ad un’interfaccia utente, ma come fornitore di un servizio ad
un’applicazione terza che può utilizzare le informazioni ricevute per presentarle a video o per altri
scopi elaborativi
4.3.1 Diagramma architetturale
La figura sottostante rappresenta il diagramma architetturale delle componenti che realizzano
il richiamo del codice legacy.
I componenti rappresentati nel diagramma sono i seguenti:

Legacy Program Interface: è una classe java che riceve in input i dati da un’applicazione
client (requester) e li prepara per il Legacy Connector. Una volta terminata l’elaborazione
del programma servente, riceve i dati dal Legacy Connector e li invia all’applicazione
richiedente come risposta alla richiesta fatta da quest’ultima.

Legacy Connector: è un insieme di classi Java, il cui scopo è quello di richiamare
un’operazione di Service Bus V4, passando i dati ricevuti dalla Legacy Program Interface.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 128 di 167
Al termine dell’esecuzione dell’operazione, l’output prodotto dal codice legacy viene
recuperato ed inviato alla Legacy Program Interface.

Codice legacy: qualsiasi programma RPG, RPG-ILE e CLP che gira su un server iSeries
sotto architettura di Modulo Base che riceva in input quale unico parametro la KPJBA e non
abbia una interfaccia a video oppure qualsiasi classe java ottenuta dalla conversione,
effettuata tramite i tool Caravel e Interactive Converter, di un programma RPG, RPG-ILE e
CLP che soddisfi le condizioni descritte nel punto precedente.

Operazione di Service Bus V4: rappresenta l’evoluzione del concetto di azione di
Modulo Base ACG in ACG Vision4, così come specificato nel paragrafo “Operazioni”. Il
codice legacy viene legato all’operazione di Service Bus, attraverso la quale viene
controllata l’autorizzazione di un utente all’esecuzione della stessa.

Database ACG: rappresenta la base dati di un sistema informativo ACG, sia nativo iSeries
che DB2 su piattaforma Win/Linux, che viene acceduta dal codice legacy associato
all’operazione di Service Bus V4

Tabelle temporanee: rappresentano un set di tabelle di lavoro che vengono utilizzate dal
codice legacy per leggere i dati in input provenienti dalla Legacy Program interface e per
restituire a quest’ultima una risposta. Sono usate tipicamente nel caso di passaggio di una
grossa mole di dati che deve essere scambiata tra applicazione client e codice legacy.
La sequenza delle operazioni può essere sintetizzata come segue:
a) La Legacy Program Interface riceve in input l’utente di collegamento, la password, il nome
del Sistema Informativo e l’indirizzo IP del server al quale collegarsi. Tali informazioni, in
alternativa, potranno essere ricavati dall’architettura, accedendo alla componente di Logon
b) La Legacy Program Interface riceve i dati in input da un’applicazione client. Si
distinguono due tipi di input:
-
dati da passare al codice legacy tramite KPJBA, inserendoli nella parte utente KPJBU
(possono cioè essere compattati in una stringa di 256 caratteri)
-
un insieme di dati che non possono essere passati attraverso la KPJBU, nel caso di una
struttura dati maggiore di 256 caratteri o di una collezione di dati (ad es. un ordine con
dati di testata ed un insieme di righe)
c) La Legacy Program Interface compatta i dati di input formando una stringa unica o un
insieme di stringhe nel caso di collection di dati. Ogni stringa rappresenta la concatenazione
ordinata dei dati ricevuti che il codice client dovrà decifrare utilizzando un’opportuna
maschera di decodifica (vale a dire tramite una DS nel caso di legacy AS/400). Nel caso di
dati non impostati dall’applicazione client (dati facoltativi) questi vengono impostati a tutti
spazi nel caso di alfanumerici o a tutti zero nel caso di valori numerici. La legacy program
interface normalizza la lunghezza di ogni stringa recuperata dal bean di input alla lunghezza
prevista per ciascun tipo dato.
Ciascuna stringa che rappresenta una struttura dati di input, sarà accompagnata
dall’informazione relativa al tipo di struttura dati che la interpreta.
L’ordine con il quale vengono ricevute le stringhe di input sarà rispettato in fase di
scrittura sulle tabelle temporanee
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 129 di 167
d) La Legacy Program Interface passa al Legacy Connector la stringa che rappresenta l’input
della KPJBU o la collezione di stringhe che rappresentano i dati da scrivere sulle tabelle
temporanee. Inoltre la Legacy Program Interface passa al Legacy Connector le informazioni
di logon (utente, password, indirizzo server e sistema informativo) se le ha ricevute in
input.
e) Il Legacy Connector recupera il logon dal server, se non ha ricevuto le credenziali di
accesso, altrimenti crea un logon utilizzando il Componente di Logon. Quindi verifica che
l’utente sia abilitato all’esecuzione dell’operazione di Modulo Base utilizzando la
Componente di autorizzazione utente
f) Il Legacy Connector crea un identificativo di transazione e costruisce la KPJBA,
impostando opportunamente la KPJBU. Nel caso in cui non debba passare dati al codice
legacy tramite KPJBU, imposta quest’ultima con l’identificativo di transazione.
g) Il Legacy Connector scrive la collezione di dati nelle tabelle temporanee e richiama
l’operazione di Service Bus V4, utilizzando una programma assimilabile all’odierno
programma BMRUN presente in ACG legacy (la chiamata viene eseguita tramite Java
Toolbox per AS/400 o framework Caravel a seconda dell’ambiente di esecuzione). Tale
programma predispone opportunamente l’ambiente di esecuzione dell’operazione di
Service Bus V4, impostando la lista delle librerie.
h) Il codice legacy associato all’operazione di Service Bus V4 legge la KPJBU ed,
eventualmente, le tabelle temporanee per recuperare i dati di input. Quindi esegue la propria
elaborazione accedendo ed aggiornando eventualmente il database, producendo stampe,
lanciando lavori batch o richiamando altri programmi che non prevedano interfaccia a video
i) Al termine dell’elaborazione il codice legacy associato all’azione di Modulo Base
restituisce il controllo al Modulo Base e questo al Legacy Connector
j) Il Legacy Connector legge la KPJBU ricevuta dal codice legacy; se questa contiene un
identificativo di transazione, vengono lette le tabelle temporanee per recuperare l’output ed
impostare i dati da inviare alla Legacy Program Interface. In caso contrario viene inviata la
KPJBU alla Legacy Program Interface.
k) La Legacy Program Interface scompatta le stringhe che rappresentano la KPJBU ed
eventualmente la collezione di dati di output, utilizzando opportune maschere di decodifica.
E’ previsto pertanto che il programma legacy possa lavorare nei modi seguenti:
a) scambiare i dati in input tramite KPJBU
b) scambiare i dati in input/output tramite tabelle temporanee
c) scambiare (opzionalmente) i dati in input/output tramite un parametro aggiuntivo di 2000
caratteri in aggiunta alla KPJBA
d) ricevere l’input tramite KPJBU e scrivere l’output sulle tabelle temporanee
e) ricevere l’input tramite tabelle temporanee e scrivere l’output nella KPJBU
Eccetto che nel primo caso, è previsto che l’identificativo di transazione dei record da
leggere/scrivere nelle tabelle temporanee sia passato tramite KPJBU. L’identificativo di transazione,
come detto, viene generato automaticamente dal Legacy Connector.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 130 di 167
L’elaborazione, in ogni caso, produce la scrittura di uno o più record nel file di log
dell’elaborazione per tracciare l’esito dell’elaborazione (segnalazione di errori o di elaborazione
terminata regolarmente).
La figura sottostante illustra l’interazione del Legacy Connector con le altre componenti
infrastrutturali di ACG Vision4 e le tabelle di database alle quali accede.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 131 di 167
4.4 Struttura delle tabelle temporanee e di log dell’elaborazione
Il file temporaneo di input (INPUT00F), il cui scopo è quello di accogliere i dati di input da
inviare al codice legacy che non possono essere passati tramite KPJBU, sarà strutturato come segue:
-
Identificativo di transazione (35A)
-
Numeratore record (intero di 9 cifre)
-
Identificativo del tipo record (10A)
-
Dati di input (2000 A)
Il file temporaneo di output (OUTPT00F), il cui scopo è quello di accogliere i dati di output
prodotti dal codice legacy che non possono essere passati tramite KPJBU, sarà strutturato come segue:
-
Identificativo di transazione (35A):
Numeratore record (intero di 9 cifre)
Identificativo del tipo record (10A)
Dati di output (2000 A)
Il file di log dell’elaborazione sarà strutturato come segue:
-
Identificativo di transazione (35A)
Tipo record (10A)
Numeratore record (9A)
Catalogo messaggi (10A)
Tipo messaggio (2,0); valori ammissibili: I=Info - W=Warn - E=Error - F=Fatal
Identificativo del messaggio (7A)
Testo del messaggio (80A)
Testo di secondo livello del messaggio (256A)
Primo campo in errore (10A)
Secondo campo in errore (10A)
Terzo campo in errore (10A)
In ciascun file la chiave univoca è rappresentata da:
-
identificativo di transazione
tipo record
numeratore record
Nei file temporanei di input e output l’identificativo di tipo record individua la struttura dati
che decodifica il contenuto dei dati che il codice legacy deve leggere o scrivere. Ad esempio, se si
devono passare al codice legacy i dati della testata di un ordine più un insieme di righe, nel file
temporaneo di input viene scritto un record per la testata, indicando nel campo “Identificativo del tipo
record” il nome della struttura dati per la decodifica della testata; analogamente verranno scritte tante
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 132 di 167
righe quante sono le righe dell’ordine, indicando come tipo record la struttura dati per la decodifica
della riga d’ordine.
Si è scelto di indicare una lunghezza di 2000 caratteri per la scrittura dei dati; nel caso
particolare che un record abbia una struttura dati di lunghezza superiore, dovranno essere scritti due o
più record con tipo differente. Sarà cura del programma chiamante scomporre la struttura su più
record diversi ed il codice legacy dovrà leggere opportunamente tali dati, ricombinandoli logicamente
a formare una struttura dati unica (si ritiene tuttavia che si tratti di una evenienza remota).
La scrittura e la lettura sui file temporanei e su quello di log dell’elaborazione sarà effettuata
da programmi generalizzati del Service Bus.
Al termine dell’elaborazione i file temporanei saranno ripuliti dei record scritti per scambiare
l’I/O con il codice legacy, su indicazione specifica dell’utente.
4.5 Amministrazione delle tabelle temporanee
La scrittura e la cancellazione di un gran numero di record nei file temporanei potrebbe
causare problemi di occupazione disco su server iSeries, nel quale la cancellazione di un record da
programma determina la cancellazione logica ma non quella fisica.
Per poter ovviare a questo inconveniente è necessario creare i file temporanei impostando il
parametro REUSEDLT ad *YES.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 133 di 167
4.6 Generazione codice Java per la Legacy program interface
La generazione del codice java di richiamo del codice legacy può essere effettuata
a) utilizzando un semplice editor per la scrittura di due file funzionali allo sviluppo e
lanciando la classe di genrazione da linea comando DOS avendo impostato opportunamente
il CLASSPATH
b) importando il progetto LegacyGenerator.jar in Rational Application Developer (RAD)
creando un progetto Java, utilizzando i tool della piattaforma di sviluppo per editare i file e
lanciare la classe di generazione.
La generazione del codice java richiede fondamentalmente la stesura di due file:
o File di property strutturato con le seguenti chiavi:
src_path=source
system=xxx.xxx.xxx.xxx
user=QPGMR
password=PWDQPGMR
libraries=ACG_OBJV4;ACG_DATV4
pkg_action=com.ibm.acgv4.xx.action
pkg_bean= com.ibm.acgv4.xx.bean
DS=ACV4DS;ADV4DS
TABLES=
ACTION=ACV4Action
essendo:
src_path: directory sorgenti progetto in RAD)
system: IP address sistema iSeries
user: utenza di servizio per il logon al sistema
password: password utenza di servizio
libraries: una lista di librerie nelle quali sono presenti tutti gli oggetti
da elaborare (file di database, DS)
pkg_action: nome del package per la classe Action
pkg_bean: nome del package per le classi bean
DS: nomi delle DS utilizzate separati da ;
TABLES: nomi dei file di database utilizzati separati da ;
ACTION: nome del file XML da utilizzare per la generazione della classe
Action
o File XML di definizione della classe Action nel formato
<?xml version="1.0" encoding='UTF-8'?>
<action actionName="AC43" actionType='AS400RPG' deleteOutput="true"
deleteInput="true" extendedParms="true" batch="true">
<configuration name="configuration" type="ConfBean"/>
<parameter name="parameter" type="AC43DS"/>
<param2 type="AC43DS"/>
<input type="INP1DS"/>
<output type="OUT1DS"/>
</action>
essendo:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 134 di 167
Elemento action ( <action actionName="AC43" ...)
Cardinalità dell’elemento = 1
actionName = nome dell’azione di Modulo Base da lanciare
actionType = tipo azione (‘AS400RPG’) per le azioni AS400
deleteOutput = specifica se deve essere cancellato il contenuto di OUTPT00F al termine
dell’esecuzione dell’azione (valori ammissibili: true o false)
deleteInput = specifica se deve essere cancellato il contenuto di INPUT00F al termine
dell’elaborazione (valori ammissibili: true o false)
extendedParams = specifica se il programma associato all’azione richiede come parametro di input
solo la KPJBA (valore impostato a false) oppure, in aggiunta al parametro di architettura, richiede il
parametro di I/O alfanumerico di 2000 caratteri
param2 = deve essere definito nell'XML in accoppiata con il parametro extendedParms impostato a
true. Specifica il nome della DS nell’attributo type da usare per l’impostazione del secondo parametro
di I/O
batch = specifica se il programma da richiamare deve essere lanciato in interattivo o in batch (valori
ammissibili: true o false; default è false in assenza dell’attributo)
Elemento configuration ( <configuration name="co ...)
Cardinalità dell’elemento = 1
Non modificare: serve ad aggiungere all’action java un’istanza della classe ConfBean da utilizzare in
alternativa all’istanza della classe com.ibm.acgv4.base.ACGLogon
Elemento parameter ( <parameter name="parameter" ...)
Cardinalità dell’elemento = 1
name = nome della variabile usate per impostare la variabile KPJBU nella KPJBA (non modificare)
type = nome del bean rappresentativo della DS da usare per impostare la KPJBU
Elemento input ( <input type=" ...)
Cardinalità dell’elemento = 0, n (vale a dire, specificare sole se il programma prevede l’acquisizione
di dati dal file INPUT00F)
type = nome del bean rappresentativo della DS da usare per scrivere nel campo DATA del file di
database INPUT00F; il nome della DS viene riportato nel campo TPREC del file INPUT00F
Elemento output ( <output type=" ...)
Cardinalità dell’elemento = 0, n (vale a dire, specificare sole se il programma prevede la scrittura di
dati nel file OUTPT00F)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 135 di 167
type = nome del bean rappresentativo della DS da usare per scrivere nel campo DATA del file di
database OUTPT00F; il nome della DS viene riportato nel campo TPREC del file OUTPT00F
I file .properties e .xml devono essere collocati nella medesima cartella
4.6.1 Lancio del code generator
Selezionare il file acg_legacy.jar, quindi le voci di menu Run – Run As – Java Application
(vedi fig.1) e successivamente selezionare la classe CodeGenerator dalla finestra RunType (vedi fig.
2).
La classe richiederà l’indicazione, nella finestra “Console”, del percorso del file di properties
da utilizzare per la generazione (ad. esempio, si può digitare gen\AC43 per eseguire la generazione a
partire da AC43.properties presente nella cartella source\gen visibile nella view “Package Explorer”
della prospettiva Java.
Al termine dell’elaborazione verranno generati una classe Action nel package relativo alle
action e una serie di bean (bean di input e di output, bean rappresentativi di DS e table)
Fig. 1
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 136 di 167
Fig. 2
Al lancio della classe di generazione verrà richiesta l’indicazione del percorso nel quale è
presente il file di property (Vedi fig. 3). Al termine dell’elaborazione effettuare il refresh del progetto
per visualizzare i file generati.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 137 di 167
Fig. 3
La classe che rappresenta la Legacy Program Interface dovrà includere il metodo runService()
che si preoccuperà di leggere i dati in input, formattarli e di passarli al Legacy Connector, insieme ad
informazioni quali il nome dell’operazione di Service Bus V4 ed il tipo di operazione ed alle
credenziali di accesso.
In ricezione dovrà recuperare la risposta dal Legacy Connector e caricarla nella collection dei
dati di output da passare all’applicazione client.
Le classi da utilizzare in fase di generazione possono essere impacchettate all’interno di una
libreria di classi java, che può essere rilasciata con un progetto WAR da importare in RAD insieme ai
package di base che realizzano le funzionalità di logon e controllo delle autorizzazioni, da cui
dipendono.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 138 di 167
4.7 Accesso tramite servizio web
Sulla base di quanto indicato precedentemente, la Legacy Program Interface è una classe java,
che avvalendosi del Legacy Connector e delle Componenti di Logon ed Autorizzazione, è in grado di
eseguire il lancio di un’operazione di Service Bus V4.
A partire da tale classe è possibile pertanto creare un web service che consenta l’invocazione
del codice legacy tramite le tecnologie standard dei web services (SOAP, WSDL, etc.). Ciò può essere
ottenuto utilizzando il wizard di generazione dei web services messo a disposizione da RAD,
indicando il metodo runService() come funzione pubblica accessibile da web service.
A tal proposito si può pensare di utilizzare il progetto di generazione del codice java per la
Legacy Program Interface per generare/aggiornare i file XML e le classi java associate ai web service.
Si ricorda che la generazione di un web service a partire da una classe java comporta, oltre alla
generazione di classi java di serializzazione e deserializzazione, anche:
-
la creazione di un file wsdl
-
la creazione di un file xml di mapping
-
l’aggiornamento del file webservices.xml
-
l’aggiornamento del file ibm-webservices-bnd.xmi
-
l’aggiornamento del file ibm-webservices-ext.xmi
Ciò richiede l’inclusione degli ultimi tre file, presenti nella web application realizzata secondo
il modello di sviluppo ACG Vision4, nel progetto di generazione dei web services al fine di
aggiornarli con l’aggiunta degli elementi che fanno riferimento al web service creato.
Dopo aver provveduto alla creazione di un web service, occorre aggiornare la web application
che consente l’accesso alle funzionalità tramite WS aggiungendo gli oggetti nuovi e sostituendo i file
xml ed xmi aggiornati.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 139 di 167
4.8 Reengineering dei programmi legacy
L’adozione di un nuovo approccio architetturale, basato sul design pattern Model-ViewController (MVC), richiede un’attività di reengineering del codice legacy finalizzata al riuso e alla
salvaguardia del codice legacy, che costituisce un patrimonio di know-how tecnico-applicativo che
conserva il proprio valore anche in un ambiente di sviluppo più evoluto.
Un programma legacy si presenta tipicamente come un monolite nel quale sono compresenti e,
spesso intrecciati tra di loro, la logica di business (algoritmi di calcolo, controlli di validità,
totalizzazioni, etc.) e di accesso al database (logica di lettura tramite codici nativi READ, READE,
CHAIN o statement SQL, istruzioni di aggiornamento e scrittura delle tabelle), quella di controllo
(che associa le variabili del database a quelle dell’interfaccia a video) e la parte di presentazione, che
gestisce l’emissione dei formati video e le interazioni con l’utente.
La migrazione ad un’architettura più moderna, multi-tier, che supporti le nuove tecnologie e
nuovi standard di presentazione, impone una riorganizzazione del codice in modo da determinare una
netta separazione tra le componenti Model e Controller da quella View, demandata, tipicamente, ad
un’interfaccia di tipo web o rich client.
Le applicazioni tradizionali 5250 interagiscono direttamente con l’utente, che, tipicamente,
seleziona un’opzione da un menu e vede presentare uno schermo. Quanto l’utente immette i dati nel
video, questi sono memorizzati in un set di variabili, che il programma mantiene in memoria finché il
programma non termina. Questi dati sono mantenuti anche se l’utente effettua ulteriori interazioni con
il programma. Questo approccio funziona in quanto il programma viene eseguito in un job associato
ad una workstation e quel job lavora solo a fronte delle richieste provenienti da quel terminale. In
questo ambiente di esecuzione, lo stato del programma viene mantenuto in variabili di programma
associate univocamente ad un solo job.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 140 di 167
Nelle applicazioni browser-based, invece, ogni richiesta utente può essere servita da un job
differente e le informazioni immesse dall’utente non possono essere mantenute in variabili di
programma poiché la volta successiva che l’utente interagisce con l’applicazione, questa può girare in
un lavoro differente. Un punto chiave da ricordare è dunque che un’applicazione browser-based può
avere delle informazioni di stato, ma queste non sono contenute in variabili di programma, ma
possono essere mantenute in un cookie e trasmesse in ogni richiesta.
Un programma legacy può essere riutilizzato in un’architettura moderna provvedendo ad
estrapolare la parte di codice strettamente legata alla gestione delle interfacce video, mantenendo le
parti (subroutine) che sono deputate all’accesso al database, sia in fase di lettura che di scrittura, al
controllo dei dati e all’implementazione della parte algoritmica di un programma.
Per quanto detto precedentemente, occorre considerare che un programma legacy fruito da client
browser o da altra applicazione dovrà essere visto come un programma state-less (privo di stato),
essendo questo contenuto o gestito direttamente dall’applicazione client che gira su un tier diverso da
quello in cui risiede il programma legacy.
Le diverse funzionalità che attengono alla logica di business e di controllo, possono essere
scritte sotto forma di routine in un programma o meglio ancora, possono essere fruibili come moduli
RPG-ILE che possono essere assemblati in un ILE service program.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 141 di 167
Le routine devono avere un’interfaccia ben definita, che rappresenti i dati che richiede in input e
quelli che fornirà in uscita. Un programma re-ingegnerizzato dovrà, pertanto, prevedere un’interfaccia
costituita da un insieme di informazioni che rappresentano i dati che dovrà trattare e le operazioni che
dovranno essere eseguite su tali dati.
I programmi legacy dovranno prevedere, tipicamente, nella loro interfaccia un codice di ritorno che
possa essere letto dall’applicazione client per verificare se un’operazione è andata a buon fine o
piuttosto sia terminata con un errore.
Il parametro da utilizzare per il passaggio dei dati ad un programma legacy sarà rappresentato
dalla KPJBA, fermo restando che, nel caso di una mole di dati più consistente, sarà necessario
ricorrere al database o ad altre soluzioni (ad esempio user space su AS/400).
Da un’ispezione effettuata sul codice ACG, appare evidente che:
-
è opportuno, nella maggior parte dei casi, scrivere un programma nuovo piuttosto che
riutilizzare un programma preesistente, modificato con l’introduzione di una serie di controlli
che servano a far funzionare lo stesso programma sia in architettura legacy che in un’architettura
più avanzata.
-
il/i programmi nuovi derivati dal codice legacy potranno includere una serie di routine che
derivino da una riscrittura di routine legacy opportunamente modificate per rimuovere i
riferimenti all’interfaccia video o all’architettura legacy (richiami a programmi che eseguono
operazioni tipiche legate all’interfaccia utente, come SNDPGMMSG, programma di ricerca con
?, etc.)
-
si deve considerare che un programma che contenga la logica di business, può essere
richiamato da contesti diversi (client web, altra applicazione, web service), per cui deve essere
predisposto a lavorare correttamente indipendentemente da chi o da come sia stato richiamato
-
laddove si vogliano avere sensibili vantaggi in termini di modularizzazione, riuso e
prestazioni, occorre far utilizzo della programmazione ILE.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 142 di 167
4.9 Table Manager
La classe TableManager consente le operazioni di lettura,scrittura, aggiornamento e
cancellazione sulle quattro tabelle standard ACG ANTA200F, ASTA300F,ANTB300F, ASTB300F.
La classe può essere utilizzata in due modalità:


utilizzando un file di properties standard
utilizzando un file di properties da fornire a runtime
4.9.1 Utilizzo tramite file di properties
Occorre utilizzare i costruttori
public TableManager(ACGLogon logon, String tableId
//deprecated)
public TableManager(ACGLogon logon, String tableId, Connection conn)
public TableManager(ACGLogon logon, String tableId, String tableCode) //deprecated)
public TableManager(ACGLogon logon, String tableId, String tableCode, Connection conn)
che prevedono che nel file table.properties presente in com.ibm.acgv4.table vi sia una entry del
tipo:
tableid=nome_tabella,file_descrittore_tabella,lunghezza_codice_elemento
(ad esempio CAU=ANTA200F,BTCAU,3). E’ prevista inoltre la presenza di un file di properties
descrittore della tabella (ad esempio BTIVA.properties, PTGEN1.properties, etc), presente in
com.ibm.acgv4.table.resources che descriva il formato record della tabella. Ad esempio, per la
tabella delle causali contabili, il file BTCAU.properties:
XDCAU=CHAR(25),1
XCAUC=CHAR(1),26
XCAUF=CHAR(1),27
XDAAV=CHAR(1),28
XRGIV=CHAR(1),29
XNREG=CHAR(1),30
…
Il file BTCAU.properties puo’ essere generato utilizzando la classe di utilità
GenerateTablePropertiesFile presente nel package com.ibm.acgv4.utils nella web-app acgv4 a cui si
passino come parametri:


Property generation file (default: CodeGenerator.properties) dando blank
Nome tabella (ad esempio BTVAL, e’ il nome della DS che descrive il tracciato record della
tabella da gestire)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 143 di 167
La classe richiede che venga reimpostato un file di properties, Profile.properties, presente o da creare
in com.ibm.acgv4.test per le credenziali di logon:
USER=ACGV4
PASSWORD=XXXXXXX
IP_ADDRESS=xxx.xxx.xxx.xxx
TYPE=AS400
Nel caso delle tabelle di personalizzazione, per le quali la DS di interpretazione del campo XDTAB
è variabile in dipendenza del codice elemento, sarà necessario utilizzare il costruttore
public TableManager(ACGLogon logon, String tableId, String tableCode) throws BaseException {
in cui


tableId deve essere impostato al nome della chiave nel table.properties
tableCode deve essere impostato con il codice della tabella
Ad esempio, nel caso della tabella di personalizzazione di Contabilità Generale, i record GEN0001 e GEN-0002 sono decodificati tramite le DS PTGEN1 e PTGEN2. In table.properties
scriveremo:
GEN_0001=ASTA300F,PTGEN1,4
GEN_0002=ASTA300F,PTGEN2,4
In com\ibm\acgv4\table\resources andremo a copiare i file PTGEN1.properties e
PTGEN2.properties descrittivi delle due DS di interpretazione dei record 1 e 2 della personalizzazione
GEN.
Per il codice scriveremo:
TableManager tm1 = new TableManager(logon, "GEN_0001", "GEN");
TableManager tm2 = new TableManager(logon, "GEN_0002", "GEN");
HashMap hm1 = tm1.read(“0001”);
HashMap hm2 = tm1.read(“0002”);
Nella classe sono disponibili i metodi:
•
public HashMap read(String elementId)
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 144 di 167
•
•
•
•
•
•
public HashMap read(String elementId, String company)
public String getBytes(HashMap values)
public void insert(String elementId, String value, char status,
String company)
public void update(String elementId, String value, char status,
String company)
public void delete(String elementId, String company)
public void changeStatus(String elementId, char status, String
company)
Il metodo read(String elementId) ritorna una HashMap contenente come chiavi i campi del file
di properties che descrive la tabella e come valori i valori corrispondenti.
Oltre al suddetto metodo, è stato aggiunto un metodo di read che riceve anche la company; in
questo secondo caso viene eseguita una read aggiungendo il codice azienda passato alla condizione di
select.
Se viene passato null, l'azienda viene impostata ad * per le tabelle che sono nella libreria
(ovvero nello schema) comune, mentre viene impostata l'azienda di logon nel caso di tabelle
aziendali.
I metodi di insert ed update, prevedono l'indicazione del codice elemento, del codice azienda
(company, passando null vale quanto detto precedentemente), il flag di stato (status, carattere blank
tipicamente, ma può essere passato qualsiasi altro carattere) e la stringa da scrivere in
XDTAB/XDATI (value).
L'annullamento e la riattivazione dell'elemento viene eseguita tramite il metodo changeStatus,
impostando opportunamente il flag status (A oppure blank).
Un valore valido della stringa può essere ottenuto usando il metodo getBytes(), che restituisce
la stringa formattata secondo la DS BTxxx/PTxxx leggendo i valori da una HashMap con le coppie
chiave-valore, in cui la chiave è al solito il campo della DS ed il valore è una stringa (per i numeri
vale usare la notazione anglosassone xxxx.xx con il punto come separatore della parte decimale).
Sample code
String tableId = "VAL";
int elemLen = 4;
TableManager tm = new TableManager(logon, tableId);
HashMap hm = tm.read(“DOL”);
Utils.printHashMap(hm, "Values for " + tableId + " - DOL ");
//Insert elemento AAAW
tm.insert("AAAW", tm.getBytes(getValuesForTest()), ' ', "*");
//Delete elemento AAAW
tm.delete("AAAW", "*");
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 145 di 167
//Tabella descrittiva
Tm = new TableManager(logon, "LIN", sqlTable, 1,
getPropertiesForDescriptiveTable(25));
hm = tm.read("F");
Utils.printHashMap(hm, "Values for " + tableId + "-" + elementId);
tm.delete("W", "*");
}
catch (BaseException be) {
....
/**
* @return
*/
private static HashMap getValuesForTest() {
HashMap values = new HashMap();
values.put("XDVAL", "Venticinque");
values.put("XDISO", "EUR");
values.put("XFLGE", "L");
values.put("XDTRE", "20080407");
values.put("XCAMF", "512.654980");
values.put("XOPRE", "0.0");
values.put("XDIVS", "1.0");
return values;
}
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 146 di 167
4.9.2 Utilizzo file di properties a runtime
In questo caso occorre specificare a runtime le informazioni che descrivono la tabella ed i
campi della tabella che si vuole gestire. Si utilizza il costruttore
public TableManager(ACGLogon logon, String tableCode, String sqlTable, int elemLen, Properties
props)
dove:
tableCode e’ il codice tabella, ad esempio VAL
sqlTable e’ la tabella SQL che contiene la tabella, ad esempio ANTA200F
elemLen e’ la lunghezza del codice elemento nella tabella, ad esempio 4
Le informazioni di struttura della tabella vanno inserite in un file di Properties costruito “ al
volo”, passato direttamente al TableManager anzichè caricarle accedendo ai file presenti in
com/ibm/acgv4/table/resources, in cui vado a specificare il formato record della tabella.
Pertanto occorre scrivere istruzioni del tipo:
Properties props = new Properties();
props.put("XDVAL", "CHAR(25),1");
props.put("XDIVS", "PACKED(5.0),26");
props.put("XOPRE", "PACKED(5.0),29");
props.put("XCAMF", "PACKED(11.6),32");
props.put("XFLGE", "CHAR(1),38");
props.put("XDTEU", "PACKED(8.0),39");
props.put("XDTRE", "PACKED(8.0),44");
props.put("XDISO", "CHAR(3),49");
try {
TableManager
props);
tm
=
new
TableManager(logon,
"VAL",
"ANTA200F",
4,
HashMap hm = tm.read(elementId);
....
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 147 di 167
oppure il file di properties potrà essere caricato usando la classe ACGPropertiesLoader
presente in com.ibm.acgv4.base come segue:
Properties props = null;
try {
props = ACGPropertiesLoader.loadProperties("com”
+ Utils.FILE_SEPARATOR
+ “ibm” + Utils.FILE_SEPARATOR + “acgv4” + Utils.FILE_SEPARATOR
+ “ca” + Utils.FILE_SEPARATOR
+ “resources” + Utils.FILE_SEPARATOR + “BTVAL.properties");
} catch (IOException e2) {
e2.printStackTrace();
}
essendo BTVAL.properties un file di proprietà costruito secondo lo standard previsto dal
TableManager.
Nel caso di tabelle descrittive è opportuno usare il secondo costruttore congiuntamente al metodo
getPropertiesForDescriptiveTable; ad esempio, nel caso della tabella lingua che ha lunghezza
dell'elemento 1 e descrizione 25 char si può scrivere:
TableManager tm = new TableManager(logon, "LIN", sqlTable, 1,
getPropertiesForDescriptiveTable(25));
HashMap hm = tm.read("F");
tm.insert("W", "Lingua W", ' ', "*");
tm.delete("W", "*");
Nel caso delle tabelle descrittive in hm sarà presente una chiave denominata XDESC il cui valore
corrisponderà alla descrizione.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 148 di 167
5. Linee guida per sviluppo funzionalità Vision4
5.1 Esecuzione Operazioni in Batch
In ACG Service Bus sono state definite le componenti architetturali per permettere l’esecuzione di
un’operazione in batch:

Panel standard per i parametri di schedulazione batch ( presente nel file ddi izionario diz.js)

Form BatchSchedulingForm da cui deve ereditare la Form che gestisce la WIN di
parametrizzazione batch ( presente nel file struts.config.xml; negli altri moduli occorre
copiare tale definizione nel file di configurazione di struts del modulo in quanto non è
supportata l’ereditarietà da form non appartenenti al modulo)

Action com.ibm.acgv4.action. ACGV4BatchSchedulingAction da cui deve ereditare l’Action
che gestisce la WIN di parametrizzazione batch

API standard per lanciare in batch l’operazione

Operazione per poter abilitare uno o più ruoli alla schedulazione avanzata con codice
ADV_SCHEDULING: all’atto dell’installazione
SYSTEM_ADM all’esecuzione di tale operazione
viene
abilitato
il
ruolo
Passi operativi
Parte View
Innanzitutto occorre definire tramite UI Wizard la Win atta a contenere il Panel Standard dei
parametri di schedulazione e uno o più panel che contengano i parametri specifici
dell’operazione da lanciare in batch.
Se l’utente è autorizzato ad eseguire una schedulazione avanzata il panel della schedulazione
apparirà come segue:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 149 di 167
La finestra contiene due bottoni:
 Esegui per schedulare il lavoro
 Annulla per chiudere la finestra senza schedulare alcunchè
Il significato dei campi del panel è il seguente:
Nome lavoro
E’ un campo in cui è possibile indicare il nome del lavoro da schedulare: esso viene concatenato con
il codice dell’operazione e data ed ora di salvataggio della schedulazione in modo da costituire una
chiave univoca per il lavoro da schedulare.
Descrizione lavoro
E’ il campo che consente di impostare uan descrizione al lavoro: esso viene concatenato con la
descrizione dell’operazione
Codice operazione
Contiene l’indicazione del codice operazione da schedulare; il campo è di solo output, in quanto preimpostato dall’Action che visualizza la WIN
Descrizione operazione
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 150 di 167
Contiene la descrizione dell’operazione da schedulare il campo è di solo output.
Frequenza
E’ un combobox a scelta singola che consente di specificare la frequenza di schedulazione.
I valori ammessi sono:
 “Una sola volta”: il lavoro sarà eseguito una sola volta ( è il valore proposto come default
 “Settimanale”: il lavoro sarà eseguito su base settimanale
 “Mensile”: il lavoro sarà eseguito su base mensile
Data pianificazione
E’ costituito da due campi che consentono di specificare la data in cui si vuole eseguire il lavoro.
E’ in alternativa al campo “Giorno Pianificazione.
Il primo campo a sinistra è un campo di tipo data impostabile anche utilizzando il componente
visuale calendario
Il secondo è un combobox a scelta singola tramite cui è possibile scegliere tra i seguenti valori :
 blank: per non specificare alcun valore (è il valore proposto come default);
 “Data corrente”: per indicare come data di schedulazione la data corrente;
 “Primo del mese”: per indicare che il lavoro deve essere eseguito il primo giorno del mese. Se
all’atto della schedulazione si è nel primo giorno del mese e non si indica l’ora di
schedulazione oppure si indica un’ora successiva a quella corrente il lavoro partirà
immediatamente o all’ora richiesta rispettivamente; se invece si indica un’ora già trascorsa il
lavoro partirà il mese successivo a quello corrente nell’ora richiesta;
 “Ultimo del mese”: per indicare che il lavoro deve essere eseguito l’ultimo giorno del mese.
Se all’atto della schedulazione si è nell’ultimo giorno del mese e non si indica l’ora di
schedulazione oppure si indica un’ora successiva a quella corrente il lavoro partirà
immediatamente o all’ora richiesta rispettivamente; se invece si indica un’ora già trascorsa il
lavoro partirà il mese successivo a quello corrente nell’ora richiesta;
I due campi sono in alternativa e quindi:
 se si imposta uan data specifica nel campo a sinistra, nel combobox occorre scegliere il valore
blank;
 se si sceglie un valore dal combobox diverso dal blank occorre non impostare il campo a
sinistra data di schedulazione.
Giorno pianificazione
Permette di specificare uno o più giorni della settimana in cui far partire il lavoro.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 151 di 167
E’ in alternativa ai campi “Data pianificazione”.
E’ un combobox a scelta multipla tramite cui è possibile specificare uno o più dei seguenti valori:
 blank: per non specificare alcun valore (è il valore proposto come default);
 “Lunedì”: per schedulare il lavoro di Lunedi’
 …….
 “Domenica”: per schedulare il lavoro di Domenica;
 “Tutti”: per schedulare il lavoro tutti i giorni.
Se si specifica blank e/o tutti non è ammessa la selezione di altri valori.
Se si specifica un valore diverso da blank, non è ammessa limpostazione dei campi di “Data
Pianificazione” e viceversa.
Se oggi è uno dei giorni della settimana specificati e l’ora specificata non è ancora trascorsa oppure
non è stata impostata il lavoro viene eseguito oggi, altrimenti il lavoro verrà eseguito alla ricorrenza
successiva del giorno specificato.
Ora pianificazione
Specifica l’ora a cui eseguire il lavoro nel formato HH:MM
Se non impostato si assume l’ora corrente al momento della schedulazione.
Giorno relativo del mese
Permette di specificare uno o più giorni relativi del mese in cui il lavoro verrà eseguito.
Questo parametro può essere impostato solo se:
 si sceglie il valore “Mensile” per la “Frequenza”
 si è scelto uno o più valori in “Giorno pianificazione” eccetto il blank
E’ un combobox a scelta multipla tramite cui è possibile specificare uno o più dei seguenti valori:
 blank: per non specificare alcun valore (è il valore proposto come default);
 “Primo” per indicare che il lavoro deve essere eseguito alla prima occorrenza del
giorno/gironi specificati in Giorno di pianificazione;
 “Secondo” per indicare che il lavoro deve essere eseguito alla seconda
giorno/gironi specificati in Giorno di pianificazione;
occorrenza del
 “Terzo” per indicare che il lavoro deve essere eseguito alla terza occorrenza del giorno/gironi
specificati in Giorno di pianificazione;
 “Quarto” per indicare che il lavoro deve essere eseguito alla quarta occorrenza del
giorno/gironi specificati in Giorno di pianificazione;
 “Quinto” per indicare che il lavoro deve essere eseguito alla quinta occorrenza del
giorno/gironi specificati in Giorno di pianificazione;
 “Ultimo” per indicare che il lavoro deve essere eseguito all’ultima occorrenza del
giorno/gironi specificati in Giorno di pianificazione;
Ad esempio se specifico i seguenti parametri:
 “Frequenza”
= “Mensile”
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 152 di 167
 “ Giorno pianificazione”
= “Martedì” + “Giovedì” (scelta multipla)
 “Giorno relativo del mese” = “Terzo”
il lavoro sarà eseguito il terzo Martedì ed il terzo Giovedì di ogni mese.
Coda
E’ una combobox a scelta singola che consente di specificare la coda (il WorkManager) in cui
eseguire il lavoro.
I valori ammessi sono:
 “Differita” se si vuol eseguire il lavoro tramite il WorkManager ACGV4_DIFFE, che
l’amministatore del sistema può creare per definire un Therad Pool con numero massimo di
lavori contemporanei posto a 1 ( valore di default impostato);
 “Immediata” se si vuol eseguire il lavoro tramite il WorkManager DefaultWorkManager,
preimpostato all’atto dell’installazione di Websphere come Thread Pool con numero massimo
di lavori contemporanei posto a 5
Se l’utente non è autorizzato ad impostare una schedulazione avanzata, la finestra di
schedulazione consentirà solamente una schedulazione “semplice” in cui è possibile eseguire
un lavoro per una sola volta ad una certa data ed ora ( viene sottesa la Frequenza “Una sola
volta”).
Si riporta un esempio di voci di dizionario relative alla finestra precedente:
// Batch sample
diz["NAV_4AppSamplesMenu"]+="|4BatchSample";
diz["LBL_IT_4BatchSample"]="Esempio Parametrico lancio batch ";
diz["LBL_EN_4BatchSample"]="Batch scheduling sample";
diz["CMD_4BatchSample"]="js:xcrtWIN('F0','WIN_BatchSampleScheduling');"
diz["LBL_IT_BatchSampleScheduling"]="Esegui";
diz["LBL_EN_BatchSampleScheduling"]="Execute";
//Action
diz["ACT_BatchSampleScheduling"]='{ "id":"BatchSampleScheduling",
"url":"../BatchSampleSchedulingAction.do?xmethod=run&xauth=N" } ';
diz["ACT_BatchSampleSchedulingCancel"]='{
"id":"BatchSampleSchedulingCancel","label":"CANCEL",
"url":"../BatchSampleSchedulingAction.do?xmethod=close&xauth=N" } ';
diz["PNL_ACGV4BatchSchedulingActions"]='{ "id":"ACGV4BatchSchedulingActions",'
+ '"bar":{ "span":"1", "buttonstyle":"width:100;" }, "actions":[ '
+ $d("ACT_BatchSampleScheduling")
+','
+ $d("ACT_BatchSampleSchedulingCancel")
+ ' ] } ';
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 153 di 167
diz["PNL_ACGV4BatchSchedulingContaining"]='{
"id":"ACGV4BatchSchedulingContaining","formId":"Form1",
"init":"true","url":"../BatchSampleSchedulingAction.do?xmethod=init&xauth=N", '
+ ' "panels":[ '
+ diz["PNL_ACGV4BatchScheduling" +','
+ diz["PNL_ACGV4BatchSchedulingActions"]
+ ' ] } ';
//Windows
diz["WIN_BatchSampleScheduling"]= '{"window":{ "id":"BatchSampleScheduling",
"width":"700", "height":"500", '
+ ' "panels":[ '
+ diz["PNL_ACGV4BatchSchedulingContaining"]
+ ' ] '
+ ' } }';
In esso come si vede è riutilizzato il pannello PNL_ACGV4BatchScheduling che contiene i
parametri
necessari
alla
schedalazione;
inoltre
è
stato
creato
il
pannello
PNL_ACGV4BatchSchedulingActions atto a contenere i bottoni che chiamano i metodi run() e close()
dell’action Struts BatchSampleSchedulingAction. All’apertura della finestra viene eseguito il metodo
init().
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 154 di 167
Parte Controller
ACG Service Bus mette a disposizione degli sviluppatori la form e l’action da cui estendere per poter
schedulare un’operazione:

Form BatchSchedulingForm da cui deve ereditare la Form che gestisce la WIN di
parametrizzazione batch ( presente nel file struts.config.xml; negli altri moduli occorre
copiare tale definizione nel file di configurazione di struts del modulo in quanto non è
supportata l’ereditarietà da form non appartenenti al modulo)

Action com.ibm.acgv4.action.ACGV4BatchSchedulingAction da cui deve ereditare l’Action
che gestisce la WIN di parametrizzazione batch
Di seguito è riportato l’estratto dello struts-config.xml che defisce Form ed Action per gestire
una elaborazione batch:
<form-bean name="BatchSampleSchedulingForm" extends="BatchSchedulingForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="PARAM1" type="java.lang.String"/>
<form-property name="PARAM2" type="java.lang.String"/>
</form-bean>
…
…
<!--Batch
Sample Action -starts-->
<action path="/BatchSampleSchedulingAction"
type="com.ibm.acgv4.action.BatchSampleSchedulingAction"
name="BatchSampleSchedulingForm" parameter="xmethod" scope="request"
input="/pages/output.vm" validate="false">
</action>
La
classe
BatchSampleSchedulingAction
deve
estendere
la
classe
ACGV4BatchSchedulingAction in modo da ereditare due metodi:
- Il metodo public void initScheduling(ActionForm form,HttpServletRequest request)
throws Exception {
che permette di inizializzare la Form di schedulazione ai dati di default ed in in base
all’autorizzazione dell’utente ad eseguire la schedulazione avanzata
 Il metodo public void schedule(ActionMapping mapping,ActionForm
form,HttpServletRequest request,Map jobParameters) throws Exception {
che consente di eseguire la schedulazione utilizzando i parametri impostati dall’utente; esso
effettua preventivamente una validazione formale dei dati immessi dall’utente
Ecco un esempio di codice dell’action per gestire la finestra:
il metodo init richiama il metodo ereditato initScheduling dopo aver impostato il codice
dell’operazione che si vuole schedulare:
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 155 di 167
public class BatchSampleSchedulingAction extends ACGV4BatchSchedulingAction {
protected Logger log = Logger.getLogger(getClass().getName());
public ActionForward init(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
DynaValidatorForm actionForm = (DynaValidatorForm) form;
debugMethod(request, actionForm, "init");
log.debug("actionForm BAtchComplex "+actionForm);
ACGLogon logon = getLogon(request, response);
setContext(actionForm, Utils.CTX_INSERT);
actionForm.set(ACGV4BatchSchedulingAction.KOPID,"PPP");
super.initScheduling(actionForm,request);
putActionFormInSession(request, actionForm, mapping);
log.debug("lista lavori in IMMED ");
return mapping.findForward("output");
}
Il metodo run() è quello che riceve quanto impostato dall’utente e tenta di schedulare
l’operazione, impostando eventualmente dei parametri tramite una HashMap: nella HashMap
è possibile caricare istanze purchè implementino l’interfaccia java.io.Serializabile.
Se NON vi sono errori chiude la finesta dando un messaggio di schedulazione avvenuta con
successo,. altrimenti salva e ritorna gli errori nella maniera usuale
public ActionForward run(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
log.debug("BatchSampleSchedulingAction FACCIO RUN ");
ACGLogon logon=null;
DynaValidatorForm actionForm = null;
try {
actionForm = (DynaValidatorForm) form;
ActionMessages errors = actionForm.validate(mapping,request);
if (!errors.isEmpty()) {
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 156 di 167
saveACGV4Errors(request, errors);
putActionFormInSession(request, actionForm, mapping);
return mapping.findForward("output");
}
logon = getLogon(request, response);
Map exampleMap=new HashMap();
exampleMap.put("ESEMPIO"," PARAMETRO DI ESEMPIO");
super.schedule(mapping,actionForm,request,exampleMap);
}
catch (BaseException b) {
log.debug(" BASEEXCEPTION errore "+ b.getMessage()+b.format(logon));
throw b;
}
catch (Exception e) {
e.printStackTrace();
throw e;
}
String CATALOGNAME = "conf.ApplicationResources";
String msgtxt="Operazione Schedulata con successo";
ResourceBundle bundle=null;
try {
bundle = ResourceBundle.getBundle( CATALOGNAME,logon.getLocale() );
msgtxt=bundle.getString("SCHED_OK");
}
catch (MissingResourceException m2)
{
m2.printStackTrace();
}
String out="xclose('"+request.getParameter(XWIN)+"','"+msgtxt+"')";
log.debug(" FACCIO CLOSE
"+ out);
addPropertyAsVector(actionForm, out, PREACTIONS);
putActionFormInSession(request, actionForm, mapping);
return mapping.findForward("output");
}
}
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 157 di 167
Parte Model
Per poter schedulare ed eseguire in maniera asincrona un’operazione occorre:
-
sviluppare uan classe java che implementi l’interfaccia org.quartz.Job o sue estensioni
-
definire un’operazione che contenga nel campo URL il nome completo di tale classe
compreso di package
Di seguito un esempio della classe java atta ad eseguita in batch: in questo caso la classe
implementa l’interfaccia InterruptableJob
estensione di Job per consentire
l’interruzione controllata del lavoro.
E’ da rimarcare che:
-
la classe java deve contenere il costruttore vuoto
-
il metodo che contiene la logica da eseguire è il metodo execute
public class SampleInterruptableObject implements InterruptableJob {
//
has the job been interrupted?
private boolean _interrupted = false;
// logging services
private static Logger _log =
Logger.getLogger(SampleInterruptableObject.class);
/**
* <p>
* Empty constructor for job initilization
* </p>
*/
public SampleInterruptableObject() {
}
/* (non-Javadoc)
* @see org.quartz.InterruptableJob#interrupt()
*/
synchronized public void interrupt() throws UnableToInterruptJobException {
System.out.println(" SETTING INTERRUPT ON
SampleInterruptableObject ");
_interrupted = true;
}
/* (non-Javadoc)
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
*/
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 158 di 167
public void execute(JobExecutionContext arg0) throws JobExecutionException {
try {
System.out.println(" EXECUTING
INTERRUPTABLE JOB ");
// main job loop... see the JavaDOC for InterruptableJob for discussion...
// do some work... in this example we are 'simulating' work by sleeping :)
//Recupero parametri
JobDataMap jMap=arg0.getJobDetail().getJobDataMap();
String operationId=(String)jMap.get("KOPID");
System.out.println(" EXECUTING
Operation
"+operationId);
ACGLogon logon=(ACGLogon) jMap.get("ACGLogon");
System.out.println(" User
"+logon.getUser());
System.out.println(" Information System
logon.getCurrentInformationSystem());
" +
String kpjba = (String) jMap.get("kpjba");
System.out.println(" KPJBA
"+kpjba);
for (int i = 0; i < 100; i++) {
try {
System.out.println(" EXECUTING
INTERRUPTABLE JOB "+i);
} catch (Exception ignore) {
ignore.printStackTrace();
}
// periodically check if we've been interrupted...
if(_interrupted) {
System.out.println(" EXECUTING
INTERRUPTABLE JOB INTERROTTO ");
_log.info("--- " + arg0.getJobDetail().getFullName() + "
Interrupted... bailing out!");
--
return; // could also choose to throw a JobExecutionException
// if that made for sense based on the particular
// job's responsibilities/behaviors
}
else
System.out.println(" EXECUTING
INTERRUPTABLE JOB NON INTERROTTO ");
}
} finally {
_log.info(arg0.getJobDetail().getFullName() + " completed at " + new Date());
}
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 159 di 167
}
}
Il metodo execute riceve come unico parametro il contesto di esecuzione JobExecutionContext
Esso conterrà i parametri impostati all’attoi della schedulazione ed in più i seguenti parametri di
contesto iniettati dal componente di schedulazione:
- il codice dell’operazione, tramite la chiave “KOPID”
- istanza di ACGLogon tramite la chiave “ACGLogon”
- la kpjba realtiva all’operazione tramite la chiave “kpjba”
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 160 di 167
5.2 Modalità di richiesta esecuzione report di IBM Cognos
tramite ACG Service Bus
In ACG Service Bus è stata resa disponibile la classe di utilità
com.ibm.acgv4.cognosInt.ACGV4CognosIntegration per richiedere l’esecuzione di un report ACG
Vision4 sul server IBM Cognos ad essa integrato.
La classe richiede che sia stato indicato nella risorsa URL acgv4/CognosServer l’indirizzo del
server Cognos che deve prendere in carico la richiesta e che il server Cognos sia stato correttamente
configurato seguendo le istruzioni presenti nella documentazione di installazione.
La classe espone diversi metodi dei quali vengono commentati i più significativi.
Essi si possono classificare in:

Metodi sincroni, cioè metodi che consentono la produzione immediata e sincrona del report, da
utilizzare all’interno di classi lanciate in batch tramite le funzionalità Vision4 o nel caso ci sia il
requirement di visualizzare immediatamente la stampa all’utente

Metodi asincroni, cioè metodi che consentono la produzione differita del report, tramite
l’utilizzo delle funzionalità di WorkManager presenti in ACG Service Bus, il cui utilizzo è il
default ACG Vision4
Metodi sincroni
public static byte[] runReport(ACGLogon logon, HttpServletRequest request, String report, int
type,HashMap parametri,boolean saveOnDB,String reportDescr) throws Exception {
Questo metodo consente di richiedere l’esecuzione sincrona di un report, il cui contenuto
viene restituito come parametro di ritorno. Il significato dei parametri è il seguente:
- istanza delle classe ACGLogon, contenente le credenziali di accesso
- istanza delle classe HttpServletRequest
- report, che è la Stringa contenente il percorso (path) del report che si vuole eseguire; un esempio
di percorso completo è il seguente:
"/content/folder[@name='ACG']/package[@name='ACG_FinanceContabile']/report[@name='A
CGFINCON018']"
- type, intero che definisce il tipo di report che si vuole ottenere; sono ammessi i seguenti valori,
codificati nella classe di integrazione stessa:
ACGV4CognosIntegration.REP_TYPE_CSV per ottenere il report in formato csv ( comma
separeted value)
ACGV4CognosIntegration.REP_TYPE_DOC per ottenere il report in formato word
ACGV4CognosIntegration.REP_TYPE_MHT per ottenere il report in formato html
ACGV4CognosIntegration.REP_TYPE_PDF per ottenere il report in formato pdf
ACGV4CognosIntegration.REP_TYPE_XLWA per ottenere il report in formato excel 2003
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 161 di 167
- parameter rappresenta i parametri necessari all’esecuzione del report in forma di HashMap (
coppia chiave-valore);
- il booleano saveOnDB che stabilisce se salvare il report nella coda di stampa ACG Vision4
(valore true) o meno (valore false)
- la stringa reportDescr che rappresenta la descrizione del report da associare ad esso all’atto del
salvataggio della stampa nella coda di stampa ACG Vision4
Il metodo restituisce il report generato sotto forma di array di bytes.
Metodi asincroni
public static void runReportAsync (ACGLogon logon, HttpServletRequest request, String report, int
type,HashMap parametri, boolean saveOnDB,String reportDescr) throws Exception {
Questo metodo consente di richiere l’esecuzione asincrona di un report. Il significato dei
parametri è identico al caso sincrono documentato in precedenza
public void runReportAsyncWithDeleteTT(ACGLogon logon, HttpServletRequest request, String
report, int type, HashMap parametri ,String reportDescr, String tableName, long jobNumber, String
jobNumeberColumnName) throws Exception {
Questo metodo consente di richiedere l’esecuzione asincrona di un report e la cancellazione dei
dati presenti in una tabella di appoggio dopo la sua generazione: la cancellazione viene effettuata in
modalità asincrona, utilizzando la coda dei lavori ACGV4_DIFFE. Il significato dei parametri è
identico al caso sincrono documentato in precedenza, salvo i seguenti parametri aggiuntivi:
- la stringa tableName è il nome della tabella contenente i dati necessari alla generazione del report
- jobNumber è il numero identificativo della elaborazione con cui sono contrassegnati i dati
necessari alla generazione del report
- la stringa jobNumberColumnName è il nome della colonna che contiene l’identificativo di
elaborazione sopracitato
In questo caso, quindi, una volta generato il report verrà richiesta la cancellazione dei dati presenti in
esso tramite l’invocazione del metodo statico clearTT(logon, tableName, jobNumber,
jobNumberColumnName) della classe CleanTTWorkUtility
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 162 di 167
Visualizzazione report eseguito in modalità sincrona
Nel caso in cui sia richiesta la produzione sincrona di report da visualizzare immediatamente
all’utente, ACG Service Bus mette a disposizione nella classe ACGDispatchAction i metodi
public ActionForward sendResponseForReport(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response, String title, int reportType, byte [] b)
Il metodo serve a preparare la risposta da inviare al client (browser): i parametri richiesti, oltre a
quelli usuali sono:
- la stringa che sarà utilizzata come titolo della finestra atta ad ospitare la visualizzazione del
report
- il tipo di report che si è in procinto di mostrare; deve essere uno dei tipi report previsti in
ACGV4CognosIntegration come specificato nei paragrafi precedenti
- l’array di byte che contiene il report, che è stato restituito dal metodo runReport() di
ACGV4CognosIntegration
public ActionForward sendResponseForErrorOnReport(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response, Exception e)
Il metodo serve a preparare la risposta da inviare al client (browser) in caso di errori ritornati
dal metodo runreport. Tra i parametri richiesti, oltre a quelli usuali, vi è la istanza di Exception
sollevata.
Il metodo dell’action di struts atto a richiedere l’esecuzione della stampa dovrà:
1. in caso di errore catturare l’eccezione ed effettuare il forward al metodo ereditato
sendResponseForErrorOnReport()
2. in caso di esecuzione eseguita con successo (nessun errore) effettuare il forward al metodo
ereditato sendResponseForReport()
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 163 di 167
5.3 Personalizzazioni in architettura ACG Vision4
5.3.1 Personalizzazione dello startup della web-application
In ACG Vision4 è possibile eseguire una o più classi allo start-up dell’applicazioni senza
necessità di dichiarare Servlet nel file web.xml (descrittore della distribuzione).
Per fare ciò occorre creare nel percorso WEB-INF\classes\conf il file custom.properties che
deve contenere una property dal nome STARTUP_SERVLET con la lista delle classi di
personalizzazione da richiamare separate da punto e virgola. Ad esempio, supponendo di aver creato
le classi mypkg.MyStartupServlet e mypkg.MyStartupServlet2 occorrerà inserire nel file
custom.properties la seguente riga:
STARTUP_SERVLET=mypkg.MyStartupServlet;mypkg.MyStartupServlet2
Le classi che vengono richiamate devono implementare il metodo
public void init(ServletConfig sc) throws Exception
essendo sc l’istanza di javax.servlet.ServletConfig inizializzata dalla web application al suo avvio.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 164 di 167
5.3.2 Personalizzazione della User Interface – posizionamento dizionari
In ACG Service Bus, al fine di ottimizzare il caricamento dei dizionari visuali (presenti nella
cartella addon/diz) è stato utilizzato l’OSS Jawr che compatta i dizionari dei diversi moduli ACG
Vision4 in file con estensione .js, denominati bundle.
Il file che dichiara i bundle specificando i dizionari che ne fanno parte si chiama
jawr.properties ed è presente in WEB-INF\classes\conf.
Il caricamento dei bundle avviene allo start-up della web application.
Il file di configurazione dei bundle associati ai dizionari di prodotto (jawr.properties) è
impostato per includere automaticamente i dizionari contenuti in cartelle predefinite in modo da
consentire la personalizzazione della User Interface dei prodotti Vision4.
Si è previsto che, qualora si voglia effettuare una personalizzazione che interessi un bundle di
un prodotto identificato dall’acronimo XXX, il personalizzatore dovrà creare le cartelle
addon/diz/customizations/XXX
addon/diz/customizations/XXX/EN
addon/diz/customizations/XXX/IT
per le definizioni degli elementi grafici
per le risorse in lingua inglese
per le risorse in lingua italiano
ed includere uno o più dizionari di personalizzazione in ciascuna cartella.
I dizionari di personalizzazione potranno sovrascrivere elementi grafici definiti nei dizionari
ACG di prodotto, così come potranno definirne di nuove.
Si riporta qui di seguito la lista dei bundle dei prodotti ACG Vision4
Prodotto
Service Bus
Amministrazione
Cespiti
Controllo di Gestione
CRM
Logistica
Produzione
Provvigioni
Ritenuta d’acconto
Tesoreria plus
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Bundle
SVB, COM
FIN, CAN, GEC
CSP
CTG
CRM
SCM
MAN
PRV
RAC
TSP
Pagina 165 di 167
5.3.3 Personalizzazione del richiamo dei report Cognos
In ACG Vision4 è previsto che i report da richiamare dalle classi java di lancio delle stampe
siano dichiarati in file di property denominati cognos_path.properties. Tali file sono ubicati in
WEB-INF\classes\conf\xxx essendo xxx il nome del modulo di appartenenza (scm per la Logistica
Vision4, man per la Produzione Vision4, etc.); per il Service Bus il file è ubicato in WEBINF\classes\conf.
Viene riportato qui di seguito un estratto di un file cognos_path.properties:
#REPORT_report_name=/content/folder[@name='ACG']/package[@name='ACG_xxx']/report[@
name='report_name']
REPORT_Articoli=/content/folder[@name='ACG']/package[@name='ACG_SVB']/report[@name
='ACGSVB0001']
REPORT_Clienti=/content/folder[@name='ACG']/package[@name='ACG_SVB']/report[@name=
'ACGSVB0002']
REPORT_Fornitori=/content/folder[@name='ACG']/package[@name='ACG_SVB']/report[@nam
e='ACGSVB0003']
La classe java di lancio di una stampa recupera il path del report cognos da lanciare accedendo
al file .properties con la chiave appropriata (nell’esempio sopra riportato, le chiavi sono
REPORT_Articoli, REPORT_Clienti e REPORT_Fornitori).
L’architettura ACG Vision4 prevede, inoltre, che prima di recuperare il file standard
cogno_path.properties venga recuperato il file cognos_path_informationSystem.properties essendo
informationSystem il nome del Sistema Informativo su cui deve girare il report. Nel caso in cui non
sia presente tale file, viene recuperato il file di default cognos_path.properties dallo stesso percorso di
prodotto. Questo meccanismo di recupero del file che contiene le informazioni sui path dei report
Cognos consente di realizzare delle personalizzazioni dei report per sistema informativo.
Pertanto, nel caso in cui si voglia personalizzare un report, è necessario:
1.
Creare un report in Cognos per copia da quello standard, specificando un nome package e
opzionalmente un nome report diversi, e personalizzarlo.
2.
Creare nella web application il file cognos_path_informationSystem.properties in WEBINF\classes\conf\module_acronym dove module_acronym è l'acronimo del prodotto Vision4 a
cui appartiene il report (scm, man, etc) e _informationSystem e' il nome del sistema
informativo (ad esempio se il sistema informativo si chiama DEMOSI ed il report appartiene
al
prodotto
Produzione,
occorre
creare
il
file
WEB-INF\classes\conf\scm\
cognos_path_DEMOSI.properties
3.
Inserire nel file di properties suddetto la chiave che rappresenta il nome del report Vision4
associandogli il path Cognos del report personalizzato creato.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 166 di 167
5.3.4 Gestione tabelle utente nei file ANTA200F, ASTA300F, ANTB300F, ASTB300F
In ACG Vision4 è prevista la possibilità, come descritto nel paragrafo 4.9, di gestire i dati
tabellari mediante la classe com.ibm.acgv4.table.TableManager, la quale è in grado di recuperare le
informazioni
di
struttura
di
una
tabella
standard
ACG
accedendo
al
file
com/ibm/acgv4/table/table.properties.
A partire dalla PTF SVB140034D del prodotto Service Bus V1R4M0 è stata data la possibilità
di recuperare le informazioni di struttura di una tabella utente (vale a dire una tabella di
personalizzazione creata da un utente) accedendo anche al file table_custom.properties, posizionato
sempre all’interno del percorso com\ibm\acgv4\table. Come per le tabelle standard ACG, una riga del
file table_custom.properties deve essere del tipo
tableid=nome_tabella,file_descrittore_tabella,lunghezza_codice_elemento
Ad esempio, se si è definita la tabella XYZ in ANTA200F con lunghezza dell’elemento 3, occorre
inserire in table_custom.properties
XYZ=ANTA200F,BTXYZ,3
Come per le tabelle stadandard ACG, occorrerà inserire in com\ibm\acgv4\table\resources il file
BTXYZ.properties descrittivo del tracciato della tabella XYZ.
© Copyright ACG Srl 2014 Tutti i diritti riservati.
Pagina 167 di 167