Devo ammettere che non mi aspettavo un simile successo, ma pare che i post Tips&Tricks suscitino davvero il gradimento di molti lettori. È per questo motivo che anche quest’oggi vi scrivo per rispondere ad una domanda che mi avete fatto spesso e per la quale avete votato in tanti: c’è un esempio pratico di lock documentale?
Quando si deve implementare il lock sulle entità di un’applicazione bisogna partire da alcune semplici domande, perché rispondendo avremo ottenuto tutte le regole necessarie per implementare il servizio:
- dove memorizzo i lock?
- come identifico i lock e le entità bloccate?
- dopo quanto tempo un lock viene considerato obsoleto?
La prima domanda nasconde un’affermazione implicita: non c’è un modo standard di memorizzare i lock applicativi. Possiamo salvarli su file XML, possiamo memorizzarli come un nuovo campo in ogni tabella di ogni entità, possiamo tenerli temporaneamente in memoria in una server session. La strada che preferisco io è l’aggiunta di una tabella locks al database.
La seconda domanda viene direttamente dalla mia risposta alla prima: se uso una sola tabella come faccio a riconoscere un lock su una Fattura da un lock su un Cliente? In questo caso viene in nostro aiuto la funzione getDNA della document orientation, che ritorna un identificativo univoco dell’entità in tutta l’applicazione. Non importa se uso i DocID o i normali contatori, un DNA è sempre univoco (all’interno dello stesso database). Per identificare correttamente i lock di tutte le entità della mia applicazione mi basterà quindi avere una tabella Locks con i campi ID, DocDNA, User, Date Time, per indicare chi e quanto ha preso un lock su quale entità.
La terza domanda arriva sempre durante l’implementazione. L’idea alla base del servizio di lock è la seguente: quando l’utente comincia a modificare un’entità allora il sistema cerca di prendere un lock, se può farlo lo scrive sul database, se non può farlo annulla la modifica e avvisa l’utente; quando l’utente smette di lavorare sull’entità il lock viene cancellato. Ma cosa succede se viene preso un lock e poi l’applicazione va in crash o il server viene riavviato o c’è un qualche errore? Succede che il lock non lo cancella nessuno e quell’entità risulta bloccata per sempre. Ecco perché bisogna arrivare ad affermare qualcosa come “dopo un giorno i lock sono considerati obsoleti e quindi nulli”.
Una volta che abbiamo risposto a queste domande passiamo all’implementazione. Come molti servizi della Document Orientation il lock documentale si basa sull’uso di un Document Helper, la classe che ci permette di globalizzare il comportamento delle classi applicative. In questo progetto di esempio ho implementato il lock usando gli eventi getLock e releaseLock.
Nel getLock verifico se l’entità modificata dall’utente è bloccata da un altro operatore cercandola per DNA, a seconda del risultato faccio qualcosa di diverso per valorizzare il parametro di input/output Result:
- se non la trovo inserisco la riga nel database, memorizzando il momento e l’utente corrente, imposto result a true;
- se la trovo e se l’utente che la blocca è l’utente corrente rinfresco il lock aggiornando l’ora, imposto result a true;
- se la trovo, se l’utente che la blocca non è l’utente corrente ma il lock è obsoleto (più vecchio di un giorno) cancello il lock e ne inserisco uno nuovo, imposto result a true;
- se la trovo, se l’utente che la blocca non è l’utente corrente e il lock non è obsoleto, imposto result a false e do un messaggio all’utente.
Provare per credere, avviate il progetto di esempio e fate il login due volte da due browser diversi usando due username diversi. Modificate una riga nel primo browser e lasciate il pannello in stato aggiornato, andate nel secondo e cercate di modificare la stessa riga. Non potrete modificare l’entità da questa seconda finestra e vedrete un errore a video.
E poi non dite che non vi penso 🙂