## FAQ: implementazione della business logic

In questa sezione sono riportate le domande più frequenti emerse durante l' utilizzo di guigen relative alla implementazione della business logic, intesa sia come scrittura dei metodi java associati agli ExecCommand sia alla modellazione di catene di comandi.

Q: quali sono i punti in cui posso inserire logica applicativa, intesa sia come comandi modellati, sia come logica custom scritta nel linguaggio target di programmazione (java)?

A: Guigen adotta il pattern command per la modellazione della logica applicativa. I punti in cui è possibile inserire i comandi che la realizzano sono:

- in corrispondenza di un EventHandler associato ad un widget o ad una voce di menu. In questo caso la logica viene eseguita a fronte dell'evento di user interaction intercettato dall'EventHandler
- in corrispondenza dell'evento implicito di onRefresh, disponibile su tutti i ContentPanel. In questo caso la logica viene eseguita:
  - prima dell'esecuzione di ogni evento di user interaction scatenato su quella schermata
  - prima del rendering della schermata
- come comando di inizializzazione dell'applicazione (onInitCommand, disponibile su ApplicationArea). In questo caso la logica viene eseguita ogni volta che si accede all'applicazione e ogni volta che si ritorna sull'url iniziale ("/")

E' importante notare che nel caso dei ContentPanel che contengono sia logica associata ad eventi di user interaction (EventHandler) sia logica da eseguire al refresh della schermata (ContentPanel.onRefreshCommand) viene eseguita prima la logica di onRefresh e successivamente la logica associata all'evento di user interaction. Se inoltre l'esito finale della catena di comandi modellata sull'EventHandler è il salto ad una differente schermata, al termine viene anche eseguita la logica di onRefresh sul ContentPanel di destinazione.

Q: Ho visto che è possibile strutturare la logica applicativa componendo catene di comandi. Sono possibili tutte le combinazioni? E' possibile utilizzare qualsiasi comando in qualsiasi dei punti possibili di attivazione (eventi, refresh,inizializzazione)?

A: I vincoli di composizione delle catene di comandi sono descritti in parte dalle caratteristiche strutturali dei comandi stessi, e in parte dipendono da ulteriori vincoli semantici (talvolta dipendenti dal contesto in cui i comandi sono utilizzati).

Di seguito un breve riassunto delle caratteristiche di componibilità dei vari comandi

#### ExecCommand

Permette di eseguire un metodo di business logic. Non ha particolari vincoli di collocazione.

#### SequenceCommand

Permette di eseguire in sequenza una serie di comandi. Ha un unico vincolo semantico: se la sequenza contiene come figli di primo livello uno tra JumpCommand, JumpExtCommand, ShowDialogCommand, NOPCommand, RefreshViewCommand , questo deve comparire come ultimo step della sequenza.

#### JumpCommand

Permette di saltare ad una differente schermata. Se inserito in un SequenceCommand deve essere l'ultimo step. Inoltre non può essere modellato in corrispondenza dell'evento implicito di onRefresh di una schermata.

#### JumpExtCommand

Permette di saltare ad un URL specifico. Se inserito in un SequenceCommand deve essere l'ultimo step. Inoltre non può essere modellato in corrispondenza dell'evento implicito di onRefresh di una schermata.

#### ShowDialogCommand

Permette di visualizzare un DialogPanel. Se inserito in un SequenceCommand deve essere l'ultimo step. Inoltre non può essere modellato in corrispondenza dell'evento implicito di onRefresh di una schermata nè come comando di inizializzazione dell'applicazione (onInitCommand). In pratica, poichè il DialogPanel è di fatto un sotto-pannello di uno specifico ContnetPanel, il comando di apertura di quel dialog può solo essere modellato a fronte di un EventHandler associato ad un widget contenuto nello stesso ContentPanel che contiene il DialogPanel.

#### NOPCommand

E'un comando ad azione nulla, serve solo per terminare correttamente la struttura delle catene di comandi. Se inserito in un SequenceCommand deve essere l'ultimo step.

#### RefreshViewCommand

Permette di effettuare il refresh selettivo della schermata. Se inserito in un SequenceCommand deve essere l'ultimo step. Inoltre non può essere modellato in corrispondenza dell'evento implicito di onRefresh di una schermata nè come comando da eseguire all'inizializzazione dell'applicazione.

#### VisibilityCommand, ONOFFCommmand

Agiscono sulla visibilità/editabilità di uno o più widget e\o menu. Ha senso solo all'interno di un ContentPanel e possono operare solo sui Widget di quel ContentPanel.

#### ScreenStateCommand

Attiva uno tra gli ScreenState di un ContentPanel. Ha senso solo all'interno di un ContentPanel e può attivare solo uno degli stati previsti per quel ContentPanel.

#### ActivateMultiPanelItemCommand

Permette di attivare uno specifico tab/step/item di un tabset/wizard/multipanel. Ha senso solo all'interno di un ContentPanel e può operare solo sui multiPanel (o sottoclassi) contenuti in quel ContentPanel.

#### ClearAppdataCommand

Permette di cancellare il valore di un ApplicationData. Non ha particolari vincoli di collocazione.

#### BeginEditStatusCommand, EndEditStatusCommand

Demarca l'inizio/fine di una sessione di editing su un certo insieme di ApplicationData, permettendo la gestione di backup del valore iniziale, ripristino del valore iniziale, verifica di avvenute modifiche rispetto al valore iniziale. Non ha particolari vincoli di collocazione.

#### CheckEditStatusCommand

Permette di verificare se, in una sessione di editing, sono state effettuate delle modifiche sui dati monitorati nella sessione. Non ha particolari vincoli di collocazione.

Q: Ho la necessità di eseguire la stessa logica applicativa a fronte di due eventi distinti su uno stesso ContentPanel. E' possibile modellare un solo ExecCommand e referenziarlo nel due punti, in modo da evitare la scrittura dello stesso codice custom java due volte?

A: No, non è possibile: gli ExecCommand devono essere distinti e genereranno due distinti metodi java nel bean spring di back-end.

E' però possibile evitare di scrivere due volte tutta la logica di business creando (nell'apposita regione protetta) un metodo che conterrà la logica vera e propria, in modo tale che nei due metodi associati ai due ExecCommand sia necessario solo effettuare il richiamo di questo metodo comune.

Q: Ho modellato un ExecCommand che ha il compito di valorizzare uno specifico ApplicationData (che non è referenziato da nessun widget della schermata). Nell'oggetto di model in input al metodo generato non è però presente nessun metodo per accedere a tale application data e non riesco pertanto a valorizzarlo. Come mai?

A: Per rendere disponibile un ApplicationData alla business logic è necessario aggiungerlo all'elenco appData dell'oggetto ContentPanel.

Q: Ho modellato un ExecCommand, ho effetutato la generazione del codice... e ora?

A: Per ogni ExecCommand viene generato un metodo nello strato business logic dove è necessario inserire la logica che si vuol far eseguire al programma.

#### dove viene generato il metodo

Il metodo corrispondente ad un ExecCommand viene generato in una classe java che viene registrata nel contesto spring. A seconda del punto in cui è modellato l'ExecCommand è differente la collocazione della classe:

- se il comando è modellato nella catena di comandi di inizializzazione dell' applicazione il metodo viene inserito nella classe `BackEndFacade`
- se il comando è modellato nella catena di comandi eseguita a fronte di un EventHandler o come comando da eseguire all'onRefresh della schermata il metodo è generato in una classe specifica di quel ContentPanel, che ha il nome `CPBE<nome del content panel>`

#### cosa ha a disposizione il metodo

La logica di business scritta nel metodo associato ad un ExecCommand può utilizzare:

- il valore di ogni ApplicationData referenziato nel ContentPanel. Per accedere a questa informazione occorre utilizzare i metodi `getAppdataXXXX()` contenuti nel parametro `theModel`. Esempio:

            		...
            		String nome = theModel.getAppdataFiltroricerca().getNome();
            		...

- il valore dei binding impliciti (deprecato) qualora per alcuni widget non sia stato impostato nessun binding esplicito. Per accedere a quest'informazione occorre utilizzare i metodi `getwidg_XXXX()` contenuti nel parametro `theModel`. Esempio:

            		...
            		String nome = theModel.getWidg_tfNome();
            		...

- l'intera sessione applicativa, per accedere alla quale è necessario utilizzare la hash-map disponibile nel parametro `theModel`. Esempio:

            		...
            		InputStream report = theModel.getSession().get("report_generato");
            		...

In presenza di alcune condizioni particolari, inoltre, sono a disposizione altre informazioni/operazioni:

- Se il ContentPanel contiene delle Table:
  - l'informazione sulla riga/colonna selezionate in un evento di click su cella:

              			...
              			String idRigaCliccata = theModel.getIdRiga();
              			Stirng idColonnaCliccata = theModel.getIdColonna();
              			...

  - il metodo `resetClearStatus_widg_<nome_tabella>` che serve per resettare lo stato di paginazione della tabella specificata. Esempio:

              			...
              			resetClearStatus_widg_myTable(themodel.getSession());
              			...

- Se il ContentPanel contiene un TabSetPanel, un WizardPanel:
  - l'informazione che permette di capire se è stato selezionato un determinato elemento (tab/step) di un determinato tabset/wizard. Queste informazioni sono valorizzate solo a fronte di un evento di cambio tab e dunque sono utilizzabili solo in un ExecCommand modellato su un EventHandler associato ad un TabSwitcher. L'utilizzo tipico è capire se è stato selezionato uno specifico tab. Nel bean spring sono disponibili alcune costanti associate al singolo tab. Esempio:

              			...
              			if (theModel.getSelectedTabValue().equals(TAB_MYTABSET_TAB1)){
              			  // e' stato selezionato il tab 'tab1' del tabset 'mytabset'
              			  ...
              			}
              			...

  - un metodo `getCurrentTab` che permette di sapere qual'è il tab (step/item) corrente all'interno di un tabset (wizard/multi). Nel bean spring sono disponibili alcune costanti associate al singolo tab e al singolo contenitore di tab. Esempio:

              			...
              			String currTabInMyTabset = getCurrentTab(theModel.getSession(), TABSET_MTABSET);
              			if (currTabInMyTabset.equals(TAB_MYTABSET_TAB1)){
              				...
              				// il tab corrente nel tabset 'mytabset' è 'tab1'
              			}
              			...

#### dove bisogna scrivere la logica

Affinchè il codice scritto manualmente sia preservato da rigenerazioni successive è necessario inserire il codice nelle apposite regioni protette.

Una regione protetta è delimitata da commenti speciali ed è identificata da un ID univoco all'interno dell'intera codeline. Esempio:

          	...
          	/*PROTECTED REGION ID(R-1222617025) ENABLED START*/
    			// inserire qui la logica applicativa da eseguire:
    			...
    		/*PROTECTED REGION END*/
    		...

#### considerazioni di design

Alcune best practices sulla scrittura della logtica di business:

- è opportuno non scrivere tutto il codice della logica applicativa all'interno delle regioni protette ma scrivere il codice strettamente necessario e delegare a oggetti ausiliari in cui è possibile concentrare la logica
- E' opportuno strutturare la logica in bean di spring hand-written dove è possibile concentrare la logica di business indipendentemente dal punto in cui sono invocate. Un pattern tipico è quello di definire dei bean con ruolo di manager la cui granularità è dipendente dal caso specifico. Per implementare questo pattern è necessario:
  1. definire la classe java che implementa il bean
  2. definire nel bean di backend i metodi get/set necessari per l' inversion of control di spring. Questi metodi devono essere definiti nell' apposita regione protetta ("property aggiuntive del bean").
  3. configurare nel file `applicationContext.xml` i bean di cui sopra
  Questo approccio può essere utilizzato anche con strutture di bean ausiliari a più livelli, ad esempio con bean di tipo dao.