= Appunti sull'implementazione = Una tabella di destinatari delle email strutturata come segue {| border=1 cellspacing=0 !Nominativo !Email !Gruppo 1 !Gruppo 2 !... |- |Alessandro Forlani |alessandro.forlani@myemail.it |(((√))) | | |- |... |} Per l'invio è stata utilizzata la libreria JavaMail (javax.mail.*). = Guida all'utilizzo = '''Importare la libreria''' di JSup L:\SUPERVIS\JSup\Librerie\InvioEmailAllarmi.jsupLib nell'applicazione in cui si vuole gestire l'invio delle email di allarme. Nello script di Startup, sia del dominio shared che del dominio user, chiamare initMailSend(). In JSup definire la '''proprietà''' sendemail.group=xxx (facendo riferimento alla tabella sopra ''xxx'' potrebbe essere ''Gruppo 1'' o ''Gruppo 2'') per i '''gruppi allarme''' per i quali si desidera che venga inviata l'email. Eventualmente definire la proprietà sendemail.group=none (oppure un altro gruppo) per i sottogruppi allarmi per i quali si vuole disabilitare l'invio (oppure specificare un altro gruppo). Nel file di '''configurazione di JSup''' (C:\Program Files (x86)\JSup\JSup.cfg) del PC che dovrà inviare le email definire il server SMTP per l'invio della posta, definendo la proprietà -Dmail.smtp.host=smtp.server.boh. Nelle [JSup Application properties#Properties|'''proprietà dell'applicazione'''] JSup definire varie proprietà: %blue%alarm.sendemail.default.%blue% * %blue%.collectMinTime%blue% = tempo minimo in minuti per il quale il sistema registra le email per un gruppo di invio, ma non le invia. * %blue%.collectMaxTime%blue% = tempo minimo in minuti per il quale il sistema registra le email per un gruppo di invio, ma non le invia. * %blue%.repetitionCheckTimeLen%blue% = intervallo di tempo (in minuti) considerato per analizzare gli allarmi ripetuti. * %blue%.repetitionMaxCount%blue% = numero massimo di ripetizioni nell'intervallo di tempo specificato da repetitionCheckTimeLen. * %blue%.longRepetitionMaxCount%blue% = numero di ripetizioni ammesse senza che tra due eventi trascorra almeno repetitionCheckTimeLen; raggiunto questo numero di eventi si ritiene che sia intervenuta un '''ripetizione lunga''' e interviene il long filter che utilizza longRepetitionMaxCount al posto di repetitionMaxCount e repetitionCheckTimeLenOnLongRepetition al posto di repetitionCheckTimeLen.
Una volta che interviene il long filter, occorre che non avvengano eventi per il tempo specificato da repetitionCheckTimeLenOnLongRepetition perché il filtro torni a funzionare con i parametri soliti (e non quelli 'long').
Se questo valore è pari a zero (default), non viene attivato il filtro per ripetizioni lunghe. * %blue%.repetitionCheckTimeLenOnLongRepetition%blue% = durata della finestra di tempo utilizzata per il controllo ripetizioni durante una ripetizione lunga (default 4 volte repetitionCheckTimeLen). * %blue%.repetitionMaxCountOnLongRepetition%blue% = numero di ripetizioni delle email ammesse nell'intervallo specificato da repetitionCheckTimeLen durante una ripetizione lunga (default 1). * %blue%.priorityFilter%blue%=1..99 specificando, ad esempio, 20 vengono inviati via email solo gli eventi relativi ad allarmi con priorità minore di 20 (compreso). * %blue%.sendForOff%blue% = 1|0 per abilitare/disabilitare l'invio delle email per eventi ritorno normale. * %blue%.sendForAck%blue% = 1|0 per abilitare/disabilitare l'invio delle email per eventi di acquisizione allarmi. * %blue%.sendUnackOnly%blue% = 1|0 per abilitare o meno la modalità di invio per la quale vengono inviati solo gli allarmi non acquisti (anche quelli già inviati). * %blue%.eventStateEvaluationPeriod%blue% = imposta ogni quanti millisecondi viene eseguita la [#Gestione notifica allarmi] (default 5000ms). * %blue%.debugEventStates%blue% = 1|0 per abilitare/disabilitare il debug del handler per la [#Gestione notifica allarmi]). * %blue%.eventAcceptFilterJavaCodeFunction%blue% = (superata: vedere [#Gestione notifica allarmi]) Nome di una [JavaCode functions] (definita nel [Domini di JSup|dominio shared]) con firma:
boolean fName(String groupName, AlarmRef alarm, AlarmEvent.EventType eventType)
che verrà chiamata per accettare gli eventi allarme da inviare via email. Questa funzione deve ritornare true per accettare un evento (e far inviare l'email al momento oppportuno) o false per rifiutare un evento e non inviare l'email. La funzione viene chiamata solo se altri criteri relativi all'invio delle email per il gruppo sono soddisfatti: sendForOff, sendForAck, priorityFilter. * %blue%.from%blue% = indirizzo email del mittente dei messaggi email inviati da [JSup] con gli allarmi. * %blue%.subject%blue% = titolo di messaggi email inviati. * %blue%.body%blue% formato per il corpo dell'email per default è ''Elenco eventi allarmi %2$:\\n%3$s''; la sintassi è la medesima usata in String.format(); i parametri inseribili sono: * 1 = il nome del gruppo; * 2 = la descrizione del gruppo (si veda sotto la proprietà alarm.sendemail.group_antincendio.body); * 3 = la lista degli allarmi da inviare. * {[JSup Math code|math expression]} (senza '%' e '$') Espressione matematica il cui risultato (di solito una stringa) viene sostituito all'espressione tra graffe, questo permette di inserire del codice condizionale e il valore corrente di [JSup tag|tag]. * %blue%.event.ACTIVE|NORMAL|ACKNOWLEDGE%blue% = Testo da visualizzare al posto degli stati in inglese degli allarmi con il parametro %4$s di format. * %blue%.format%blue% formato da utilizzare per comporre la linea con gli allarmi, la sintassi è la medesima usata in String.format(); i parametri utilizzabili sono i seguenti: {| |width=45| |Visualizza parametri: * 1 = date * 2 = time * 3 = tag name * 4 = state * 5 = priority * 6 = alarm name * 7 = alarm group name * 8 = alarm description * 9 = time: custom formattable * 10 = username (only for acknowledge events) * 11 = user comment (only for acknowledge events) * 12 = user hostname (only for acknowledge events) * 13 = username@hostname: comment (only for acknowledge events) * 14 = last active/non active state change date * 15 = last active/non active state change time * 16 = last active/non active state change (custom formattable) Di default il formato è "%1$s $2$s %6$20s %4$11s %5$2d %7$20s %8$s %13$s". |} Le proprietà specificate sopra possono essere '''personalizzate per un gruppo allarmi''' (per esempio ''antincendio'') utilizzando delle proprietà alarm.sendemail.group_antincendio.collectMinTime ecc. Oltre alle proprietà elencate qui sopra per il default dei gruppi, è possibile definire: * %blue%.description%blue% = descrizione del gruppo allarme che è possibile inserire nel alarm.sendemail.group_antincendio.body (se non viene specificato viene usato il nome del gruppo). * %blue%.expireMin%blue% tempo (in minuti) dopo il quale una mail che non è stato possibile spedire (problemi con il server SMTP) verrà considerata scaduta e verrà eliminata senza essere spedita. Il valore di default è -1 che indica di utilizzare la proprietà mail.defaultExpireAfter del file di configurazione [JSup.cfg]. Impostando il valore 0 si tenterà di inviare le email immediatamente, se non è possibile la mail verrà scartata, ma verranno mantenuti gli eventi da segnalare e, all'invio successivo, sarà tentato l'invio di una nuova mail con la situazione aggiornata degli allarmi da segnalare. Esempio di configurazione: alarm.sendemail.default.body=ALLARMI NON ACQUISITI %2$S:\n%3$s\n\nEmail inviata automaticamente dal sistema di supervisione.\nSi prega di non rispondere. alarm.sendemail.default.collectMaxTime=10 alarm.sendemail.default.collectMinTime=1 alarm.sendemail.default.event.ACKNOWLEDGE=-ACQUISIZIONE- alarm.sendemail.default.event.ACTIVE=----ATTIVO---- alarm.sendemail.default.event.NORMAL=--NON ATTIVO-- alarm.sendemail.default.format=%4$15s %14$s %15$s %8$s [%6$s] alarm.sendemail.default.from=allarmi.plantname@customer.com alarm.sendemail.default.repetitionCheckTimeLen=60 alarm.sendemail.default.repetitionMaxCount=6 alarm.sendemail.default.sendForAck=0 alarm.sendemail.default.sendForOff=1 alarm.sendemail.default.sendUnackOnly=1 alarm.sendemail.default.subject=Allarme da supervisore XXXXX alarm.sendemail.default.expireMin=2880 = Gestione notifica allarmi = E' stata aggiunta la possibilità di gestire in maniera estesa la notifica degli allarmi via email. Questo viene fatto tramite una gestione degli stati per ogni evento, che vengono gestiti e modificati da un oggetto che implementa l'interfaccia EventCollector.EventStateHandler, ovvero il metodo int handleEvent( final AlarmEvent event, final int currentState ) che ottiene un evento da gestire, il suo stato corrente e deve ritornare il nuovo stato (o il medesimo se non cambia). Gli stati base sono i seguenti (si tratta di costanti int): * STATE_new: stato assegnato ad un evento appena creato (anche se non viene cambiato dall'handler, viene comunque cambiato in STATE_waiting al termine del primo handle) * STATE_forget: assegnare questo stato per far scartare l'evento, non inviarlo via email e non processarlo più. * STATE_waiting: stato predefinito per un evento non ancora processato (un evento in stato STATE_new passa automaticamente a questo stato se non esplicitamente cambiato al primo handle) * STATE_hold: l'evento è trattenuto e non viene inviato anche se avviene una notifica di eventi. * STATE_notifyNoTrig: richiesta di notificare l'evento, ma senza avviare un notifica per questo evento: se una notifica avverrà ci sarà anche questo evento. Assegnando questo stato, l'evento verrà tolto dall'elenco degli eventi in valutazione (handle) e passato per la notifica. * STATE_notify: richiesta di notificare l'evento e di avviare la notifica secondo le regole (ritardi, ripetizioni, ecc.) di questo collector * STATE_FIRST_CUSTOM: se si vogliono definire degli stati customizzati, il loro valore dev'essere maggiore o uguale di STATE_FIRST_CUSTOM. Per definire e attivare l'hadler della notifica degli allarmi via email basta seguire il seguente esempio. Nella funzione initMailSend(), prima di creare i gruppi di notifica allarmi via email (mailSendGroups = new MailSendGroups(...)), definire l'oggetto che si occuperà di gestire la notifica degli allarmi: // impostazione filtro eventi final AlarmEventStateHandler aesh = new AlarmEventStateHandler(); setAlarmNotificationStateHandler( aesh ); Esempio di implementazione di AlarmEventStateHandler private static class AlarmEventStateHandler implements EventCollector.EventStateHandler { final static String caption = "EventStateHandler: "; public int handleEvent( final AlarmEvent event, final int currentState ) { try { int nextState = currentState; final AlarmRef alarm = event.getAlarmRef(); switch( currentState ) { case EventCollector.Event.STATE_new: case EventCollector.Event.STATE_waiting: { final boolean noEmail = Tools.toBool( alarm.getProperty("noEmail", null) ); if( noEmail ) { System.err.println( caption+"noEmail: "+alarm ); nextState = EventCollector.Event.STATE_forget; break; } if( !event.getAlarmRef().isToAck() ) { if( currentState == EventCollector.Event.STATE_new ) System.err.println( caption+"acquisito: "+alarm ); nextState = EventCollector.Event.STATE_forget; break; } final boolean noEmailDiSera = Tools.toBool( alarm.getProperty("noEmailDiSera", null) ); if( noEmailDiSera && ($Hour >= 20 || $Hour < 7) ) { if( currentState == EventCollector.Event.STATE_new ) System.err.println( caption+"noEmailDiSera: "+alarm ); nextState = EventCollector.Event.STATE_waiting; break; } if( Digital_dummy ) nextState = EventCollector.Event.STATE_notify; } } return nextState; } catch( JException e ) { return currentState; } } } Esempio 2 private static class AlarmEventStateHandler implements EventCollector.EventStateHandler { final static String caption = "EventStateHandler: "; public int handleEvent( final AlarmEvent event, final int currentState ) { try { int nextState = currentState; final AlarmRef alarm = event.getAlarmRef(); switch( currentState ) { case EventCollector.Event.STATE_new: case EventCollector.Event.STATE_waiting: { final boolean noEmail = Tools.toBool( alarm.getProperty("noEmail", null) ); if( noEmail ) { System.err.println( caption+"noEmail: "+alarm ); nextState = EventCollector.Event.STATE_forget; break; } if( alarm.getTag().getName().equals( "A_SSL_Contatore2_com" ) ) { nextState = EventCollector.Event.STATE_hold; break; } if( alarm.getTag().getName().equals( "A_SSL_Contatore3_com" ) ) { nextState = EventCollector.Event.STATE_notifyNoTrig; break; } if( alarm.getTag().getName().equals( "A_SSL_Contatore4_com" ) ) { nextState = EventCollector.Event.STATE_notify; break; } if( !event.getAlarmRef().isToAck() ) { if( currentState == EventCollector.Event.STATE_new ) System.err.println( caption+"acquisito: "+alarm ); nextState = EventCollector.Event.STATE_forget; break; } final boolean noEmailDiSera = Tools.toBool( alarm.getProperty("noEmailDiSera", null) ); if( noEmailDiSera && ($Hour >= 20 || $Hour < 7) ) { if( currentState == EventCollector.Event.STATE_new ) System.err.println( caption+"noEmailDiSera: "+alarm ); nextState = EventCollector.Event.STATE_waiting; break; } if( Digital_dummy ) nextState = EventCollector.Event.STATE_notify; } } return nextState; } catch( JException e ) { return currentState; } } }