DatiCollezionatiDistributedRedisAtomicLong.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2026 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.pdd.core.controllo_traffico.policy.driver.redisson.counters;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.openspcoop2.core.controllo_traffico.beans.ActivePolicy;
import org.openspcoop2.core.controllo_traffico.beans.DatiCollezionati;
import org.openspcoop2.core.controllo_traffico.beans.IDUnivocoGroupByPolicyMapId;
import org.openspcoop2.core.controllo_traffico.beans.IDatiCollezionatiDistributed;
import org.openspcoop2.core.controllo_traffico.constants.TipoControlloPeriodo;
import org.openspcoop2.pdd.core.controllo_traffico.policy.driver.ActiveRequestDistributedIntervalManager;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.core.controllo_traffico.policy.driver.BuilderDatiCollezionatiDistributed;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.utils.SemaphoreLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
/**
* Scelgo questa implementazione, dove la versione distribuita eredita da DatiCollezionati e replica i dati da distribuitre.
* In questo modo, le varie PolicyGroupByActiveThreads* continueranno a restituire un oggetto di tipo DatiCollezionati. Con dati che sono presenti
* nella ram del nodo locale, evitando così che il PolicyVerifier o altre classi che utilizzano i DatiCollezionatiDistributed vadano
* a fare richieste remote, ottenendo valori che non sono quelli che ci si aspettava dopo la richiesta.
*
* @author Francesco Scarlato (scarlato@link.it)
* @author $Author$
* @version $Rev$, $Date$
*
*/
public class DatiCollezionatiDistributedRedisAtomicLong extends DatiCollezionati implements IDatiCollezionatiDistributed{
private static final long serialVersionUID = 1L;
private final transient org.openspcoop2.utils.Semaphore lock = new org.openspcoop2.utils.Semaphore("DatiCollezionatiDistributedRedisAtomicLong");
private final transient RedissonClient redisson;
private final IDUnivocoGroupByPolicyMapId groupByPolicyMapId;
private final int groupByPolicyMapIdHashCode;
// TTL configuration per la pulizia automatica dei contatori
private final transient RedisTTLConfig ttlConfig;
// TTL config per contatori senza intervallo temporale (es. policyDate, updatePolicyDate)
// Questi contatori devono avere renewTTLOnWrite=true per rimanere attivi
private final transient RedisTTLConfig ttlConfigNoInterval;
// TTL config per activeRequestCounter quando intervalloSecondi > 0:
// il contatore viene rimpiazzato ogni intervallo, quindi il TTL iniziale e' sufficiente
// e non serve rinnovarlo ad ogni scrittura (renewTTLOnWrite=false)
private final transient RedisTTLConfig ttlConfigActiveRequestInterval;
// data di registrazione/aggiornamento policy
// final: sono i contatori che non dipendono da una finestra temporale
// sono rimasti AtomicLong le date
private final transient DatoRAtomicLong distributedUpdatePolicyDate; // data di ultima modifica della policy
private final transient DatoRAtomicLong distributedPolicyDate; // intervallo corrente su cui vengono costruiti gli altri contatori
private transient DatoRAtomicLong distributedPolicyRequestCounter; // numero di richieste effettuato nell'intervallo
private transient DatoRAtomicLong distributedPolicyCounter; // utilizzato per tempi o banda
private final transient DatoRAtomicLong distributedPolicyDegradoPrestazionaleDate; // intervallo corrente su cui vengono costruiti gli altri contatori
private transient DatoRAtomicLong distributedPolicyDegradoPrestazionaleRequestCounter; // numero di richieste effettuato nell'intervallo
private transient DatoRAtomicLong distributedPolicyDegradoPrestazionaleCounter; // contatore del degrado
private final boolean distribuitedActiveRequestCounterPolicyRichiesteSimultanee;
private transient DatoRAtomicLong distributedActiveRequestCounterForStats; // numero di richieste simultanee
private transient DatoRAtomicLong distributedActiveRequestCounterForCheck; // numero di richieste simultanee
// Gestione intervalli per richieste simultanee (per evitare contatori orfani in ambienti distribuiti)
private final transient int richiesteSimultaneeIntervalloSecondi; // intervallo in secondi, <= 0 disabilitato
private final transient DatoRAtomicLong distributedActiveRequestCounterDate; // data intervallo corrente (solo se intervallo > 0)
private transient DatoRAtomicLong distributedPolicyDenyRequestCounter; // policy bloccate
// Cache locale per evitare round-trip Redis nel hot path (intervallo cambia ~1 volta/ora)
private volatile long lastKnownActiveRequestIntervalDate = -1;
private volatile long lastCheckedIntervalStartForCheck = -1;
private volatile long lastCheckedIntervalStartForStats = -1;
// I contatori da eliminare
// Se si effettua il drop di un contatore quando si rileva il cambio di intervallo, potrebbe succedere che in un altro nodo del cluster che sta effettuando la fase di 'end'
// non rilevi più il contatore e di fatto quindi lo riprende partenzo da 0. Poi a sua volta capisce il cambio di intervallo e lo rielimina.
// per questo motivo, il drop viene effettuato al secondo cambio di intervallo, e ad ogni cambio i contatori vengono collezionati nel cestino
private transient List<DatoRAtomicLong> cestinoPolicyCounters = new ArrayList<>();
private transient List<DatoRAtomicLong> cestinoPolicyCountersDegradoPrestazionale = new ArrayList<>();
private transient List<DatoRAtomicLong> cestinoActiveRequestCounters = new ArrayList<>();
private boolean initialized = false;
private static Logger getLogControlloTraffico() {
boolean debug = false;
try {
debug = OpenSPCoop2Properties.getInstance().isControlloTrafficoDebug();
} catch(Exception e) {
// ignore
}
return OpenSPCoop2Logger.getLoggerOpenSPCoopControlloTraffico(debug);
}
public DatiCollezionatiDistributedRedisAtomicLong(Logger log, Date updatePolicyDate, Date gestorePolicyConfigDate, RedissonClient redisson, IDUnivocoGroupByPolicyMapId groupByPolicyMapId, ActivePolicy activePolicy) {
super(updatePolicyDate, gestorePolicyConfigDate);
this.redisson = redisson;
this.groupByPolicyMapId = groupByPolicyMapId;
this.groupByPolicyMapIdHashCode = this.groupByPolicyMapId.hashCode();
// Inizializza configurazione TTL basata sulla policy
this.ttlConfig = RedisTTLConfig.fromPolicy(activePolicy);
// TTL config per contatori senza intervallo (policyDate, updatePolicyDate)
this.ttlConfigNoInterval = RedisTTLConfig.forCountersWithoutInterval();
this.initDatiIniziali(activePolicy);
this.checkDate(log, activePolicy); // inizializza le date se ci sono
this.distributedPolicyDate = this.initPolicyDate();
this.distributedUpdatePolicyDate = this.initUpdatePolicyDate();
this.distributedPolicyDegradoPrestazionaleDate = this.initPolicyDegradoPrestazionaleDate();
this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee = activePolicy.getConfigurazionePolicy().isSimultanee() &&
TipoControlloPeriodo.REALTIME.equals(activePolicy.getConfigurazionePolicy().getModalitaControllo());
// Inizializza l'intervallo per le richieste (per tutte le policy, non solo richieste simultanee)
this.richiesteSimultaneeIntervalloSecondi = ActiveRequestDistributedIntervalManager.getIntervalloSecondi();
this.distributedActiveRequestCounterDate = initActiveRequestCounterDate();
// TTL config per activeRequestCounter con intervallo: il contatore viene rimpiazzato
// periodicamente, quindi basta il TTL iniziale senza rinnovo ad ogni scrittura
this.ttlConfigActiveRequestInterval = initTTLConfigActiveRequestInterval();
if(this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee){
this.distributedActiveRequestCounterForCheck = this.initActiveRequestCounters(getActiveRequestCounterIntervalDate());
this.distributedActiveRequestCounterForStats = null;
}
else {
this.distributedActiveRequestCounterForStats = this.initActiveRequestCounters(getActiveRequestCounterIntervalDate());
}
if(this.policyRealtime!=null && this.policyRealtime){
initPolicyCounters(super.getPolicyDate().getTime());
}
if(this.policyDegradoPrestazionaleRealtime!=null && this.policyDegradoPrestazionaleRealtime){
initPolicyCountersDegradoPrestazionale(super.getPolicyDegradoPrestazionaleDate().getTime());
}
// Gestisco la updatePolicyDate qui.
// se updatePolicyDate è > this.distributedUpdatePolicyDate.get() allora resetto i contatori del cluster e setto la nuova data distribuita.
// Questo per via di come funziona l'aggiornamento delle policy: i datiCollezionati correnti per una map<IDUnivoco..., DatiCollezionati> vengono cancellati e reinizializzati.
// Per gli altri nodi in esecuzione, la updatePolicyDate locale resta sempre la stessa, ma non viene usata.
if(this.policyRealtime!=null && this.policyRealtime &&
updatePolicyDate != null && this.distributedUpdatePolicyDate!=null && this.distributedUpdatePolicyDate.get() < updatePolicyDate.getTime()) {
this.resetCounters(updatePolicyDate);
}
this.initialized = true;
}
public DatiCollezionatiDistributedRedisAtomicLong(Logger log, DatiCollezionati dati, RedissonClient redisson, IDUnivocoGroupByPolicyMapId groupByPolicyMapId, ActivePolicy activePolicy) {
super(dati.getUpdatePolicyDate(), dati.getGestorePolicyConfigDate());
if(log!=null) {
// nop
}
// Inizializzo il padre con i valori in RAM, dopo uso 'super' per essere sicuro di usare quelli
dati.setValuesIn(this, false);
this.redisson = redisson;
this.groupByPolicyMapId = groupByPolicyMapId;
this.groupByPolicyMapIdHashCode = this.groupByPolicyMapId.hashCode();
// Inizializza configurazione TTL basata sulla policy
this.ttlConfig = RedisTTLConfig.fromPolicy(activePolicy);
// TTL config per contatori senza intervallo (activeRequestCounter, policyDate)
this.ttlConfigNoInterval = RedisTTLConfig.forCountersWithoutInterval();
this.distributedPolicyDate = this.initPolicyDate();
this.distributedUpdatePolicyDate = this.initUpdatePolicyDate();
this.distributedPolicyDegradoPrestazionaleDate = this.initPolicyDegradoPrestazionaleDate();
this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee = activePolicy.getConfigurazionePolicy().isSimultanee() &&
TipoControlloPeriodo.REALTIME.equals(activePolicy.getConfigurazionePolicy().getModalitaControllo());
// Inizializza l'intervallo per le richieste (per tutte le policy, non solo richieste simultanee)
this.richiesteSimultaneeIntervalloSecondi = ActiveRequestDistributedIntervalManager.getIntervalloSecondi();
this.distributedActiveRequestCounterDate = initActiveRequestCounterDate();
// TTL config per activeRequestCounter con intervallo: il contatore viene rimpiazzato
// periodicamente, quindi basta il TTL iniziale senza rinnovo ad ogni scrittura
this.ttlConfigActiveRequestInterval = initTTLConfigActiveRequestInterval();
if(this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee){
this.distributedActiveRequestCounterForCheck = this.initActiveRequestCounters(getActiveRequestCounterIntervalDate());
this.distributedActiveRequestCounterForStats = null;
}
else {
this.distributedActiveRequestCounterForStats = this.initActiveRequestCounters(getActiveRequestCounterIntervalDate());
}
// Se non ho la policyDate, non considero il resto delle informazioni, che senza di essa non hanno senso.
if (super.getPolicyDate() != null) {
// Non serve: essendo già persistente, si va a sommare un dato gia' esistente
/**
// Se ci sono altri nodi che stanno andando, la distributedPolicyDate DEVE essere != 0
if (this.distributedPolicyDate.compareAndSet(0, super.getPolicyDate().getTime())) {
// Se la data distribuita non era inizializzata e questo nodo l'ha settata, imposto i contatori come da immagine bin.
// Faccio la addAndGet, in quanto tutti valori positivi, non entriamo in conflitto con gli altri nodi che stanno effettuando lo startup nello stesso momento
Long polDate = super.getPolicyDate().getTime();
initPolicyCounters(polDate);
Long getPolicyRequestCounter = super.getPolicyRequestCounter(true);
if (getPolicyRequestCounter != null) {
this.distributedPolicyRequestCounter.addAndGet(getPolicyRequestCounter);
}
Long getPolicyDenyRequestCounter = super.getPolicyDenyRequestCounter(true);
if (getPolicyDenyRequestCounter != null) {
this.distributedPolicyDenyRequestCounter.set(getPolicyDenyRequestCounter);
}
if(this.tipoRisorsa==null || !isRisorsaContaNumeroRichieste(this.tipoRisorsa)){
Long getPolicyCounter = super.getPolicyCounter(true);
if (getPolicyCounter != null) {
this.distributedPolicyCounter.addAndGet(getPolicyCounter);
}
}
Long getActiveRequestCounter = super.getActiveRequestCounter(true);
if (getActiveRequestCounter!=null && getActiveRequestCounter != 0) {
if(this.distribuitedActiveRequestCounter_policyRichiesteSimultanee){
this.distributedActiveRequestCounterForCheck.set(getActiveRequestCounter);
}
else {
this.distributedActiveRequestCounterForStats.set(getActiveRequestCounter);
}
}
} else {
*/
Long polDate = null;
if(this.distributedPolicyDate!=null) {
polDate = this.distributedPolicyDate.get();
// Assicura che il TTL sia applicato anche se il contatore è stato creato da un altro nodo
this.distributedPolicyDate.ensureTTLApplied();
}
initPolicyCounters(polDate);
/**}*/
}
// Se non ho la policyDegradoPrestazionaleDate, non considero il resto delle informazioni, che senza di essa non hanno senso.
if(this.policyDegradoPrestazionaleRealtime!=null && this.policyDegradoPrestazionaleRealtime &&
super.getPolicyDegradoPrestazionaleDate() != null) {
// Non serve: essendo già persistente, si va a sommare un dato gia' esistente
/**
// Imposto i contatori distribuiti solo se nel frattempo non l'ha fatto un altro thread del cluster.
if (this.distributedPolicyDegradoPrestazionaleDate.compareAndSet(0, super.getPolicyDegradoPrestazionaleDate().getTime())) {
Long degradoPrestazionaleTime = super.getPolicyDegradoPrestazionaleDate().getTime();
initPolicyCountersDegradoPrestazionale(degradoPrestazionaleTime);
Long getPolicyDegradoPrestazionaleRequestCounter = super.getPolicyDegradoPrestazionaleRequestCounter(true);
if (getPolicyDegradoPrestazionaleRequestCounter != null) {
this.distributedPolicyDegradoPrestazionaleRequestCounter.addAndGet(getPolicyDegradoPrestazionaleRequestCounter);
}
Long getPolicyDegradoPrestazionaleCounter = super.getPolicyDegradoPrestazionaleCounter(true);
if (getPolicyDegradoPrestazionaleCounter != null) {
this.distributedPolicyDegradoPrestazionaleCounter.addAndGet(getPolicyDegradoPrestazionaleCounter);
}
} else {
*/
Long degradoPrestazionaleTime = null;
if(this.distributedPolicyDegradoPrestazionaleDate!=null) {
degradoPrestazionaleTime = this.distributedPolicyDegradoPrestazionaleDate.get();
// Assicura che il TTL sia applicato anche se il contatore è stato creato da un altro nodo
this.distributedPolicyDegradoPrestazionaleDate.ensureTTLApplied();
}
initPolicyCountersDegradoPrestazionale(degradoPrestazionaleTime);
/**}*/
}
this.initialized = true;
}
private DatoRAtomicLong initPolicyDate() {
if(this.policyRealtime!=null && this.policyRealtime){
// Usa ttlConfigNoInterval perché policyDate non è un contatore di intervallo:
// mantiene il timestamp dell'intervallo corrente e vive attraverso più finestre temporali
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_POLICY_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigNoInterval);
}
return null;
}
private DatoRAtomicLong initUpdatePolicyDate() {
if(this.policyRealtime!=null && this.policyRealtime){
// Usa ttlConfigNoInterval perché updatePolicyDate non è un contatore di intervallo
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode
+BuilderDatiCollezionatiDistributed.DISTRUBUITED_UPDATE_POLICY_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigNoInterval);
}
return null;
}
private DatoRAtomicLong initPolicyDegradoPrestazionaleDate() {
if(this.policyDegradoPrestazionaleRealtime!=null && this.policyDegradoPrestazionaleRealtime){
// Usa ttlConfigNoInterval perché policyDegradoPrestazionaleDate non è un contatore di intervallo
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_POLICY_DEGRADO_PRESTAZIONALE_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigNoInterval);
}
return null;
}
private DatoRAtomicLong initActiveRequestCounterDate() {
// Crea il contatore per la data dell'intervallo solo se la gestione a intervalli è abilitata
if(this.richiesteSimultaneeIntervalloSecondi > 0) {
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_POLICY_DATE+
"activeRequest"+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigNoInterval);
}
return null;
}
@Override
protected Long getActiveRequestCounterIntervalDate() {
if(this.richiesteSimultaneeIntervalloSecondi <= 0) {
return null;
}
// Fast path locale: se il cached e' gia' nell'intervallo corrente, non serve andare su Redis
long currentIntervalStart = ActiveRequestDistributedIntervalManager.calcolaIntervalloCorrente(this.richiesteSimultaneeIntervalloSecondi);
long cached = this.lastKnownActiveRequestIntervalDate;
if(cached > 0 && cached >= currentIntervalStart) {
return cached;
}
// Solo alla prima chiamata o al cambio intervallo si va su Redis
if(this.distributedActiveRequestCounterDate != null) {
long distributedDate = this.distributedActiveRequestCounterDate.get();
if(distributedDate == 0) {
// Prima inizializzazione
this.distributedActiveRequestCounterDate.compareAndSet(0, currentIntervalStart);
this.lastKnownActiveRequestIntervalDate = currentIntervalStart;
return currentIntervalStart;
} else if(distributedDate < currentIntervalStart) {
// L'intervallo è cambiato, prova ad aggiornare
if(this.distributedActiveRequestCounterDate.compareAndSet(distributedDate, currentIntervalStart)) {
this.lastKnownActiveRequestIntervalDate = currentIntervalStart;
return currentIntervalStart;
}
// Un altro nodo ha già aggiornato, leggi il nuovo valore
long newDate = this.distributedActiveRequestCounterDate.get();
this.lastKnownActiveRequestIntervalDate = newDate;
return newDate;
}
this.lastKnownActiveRequestIntervalDate = distributedDate;
return distributedDate;
}
this.lastKnownActiveRequestIntervalDate = currentIntervalStart;
return currentIntervalStart;
}
@Override
protected String getPolicyIdForContext() {
return String.valueOf(this.groupByPolicyMapIdHashCode);
}
private RedisTTLConfig initTTLConfigActiveRequestInterval() {
if(this.richiesteSimultaneeIntervalloSecondi > 0 && this.ttlConfigNoInterval != null && this.ttlConfigNoInterval.isEnabled()) {
// Con intervalloSecondi > 0, il contatore viene rimpiazzato ogni intervallo.
// Il TTL deve coprire almeno 2 intervalli (il corrente + il cestino), si usa ×3 per sicurezza.
// renewTTLOnWrite=false perché non serve rinnovare: il contatore ha vita limitata.
return new RedisTTLConfig(true, ((long)this.richiesteSimultaneeIntervalloSecondi) * 3L, false);
}
return this.ttlConfigNoInterval;
}
private DatoRAtomicLong initActiveRequestCounters(Long intervalDate) {
// Se intervalDate è valorizzato, crea un contatore con timestamp nel nome (gestione a intervalli)
// Altrimenti crea un contatore senza timestamp (comportamento legacy)
if(intervalDate != null && intervalDate > 0) {
// Usa ttlConfigActiveRequestInterval: TTL=intervalloSecondi×3, renewTTLOnWrite=false
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_ACTIVE_REQUEST_COUNTER+
intervalDate+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_SUFFIX_CONFIG_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigActiveRequestInterval);
} else {
// Usa ttlConfigNoInterval perché activeRequestCounter non ha un intervallo temporale:
// conta le richieste attive in quel momento e deve rimanere attivo finché il client fa richieste
return new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_ACTIVE_REQUEST_COUNTER+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfigNoInterval);
}
}
private void initPolicyCounters(Long policyDate) {
if(this.policyRealtime!=null && this.policyRealtime){
this.distributedPolicyRequestCounter = new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_POLICY_REQUEST_COUNTER+
policyDate+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_SUFFIX_CONFIG_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfig);
this.distributedPolicyDenyRequestCounter = new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_POLICY_DENY_REQUEST_COUNTER+
policyDate+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_SUFFIX_CONFIG_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfig);
if(this.tipoRisorsa==null || !isRisorsaContaNumeroRichieste(this.tipoRisorsa)){
this.distributedPolicyCounter = new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_POLICY_COUNTER+
policyDate+
BuilderDatiCollezionatiDistributed.DISTRUBUITED_SUFFIX_CONFIG_DATE+
(this.gestorePolicyConfigDate!=null ? this.gestorePolicyConfigDate.getTime() : -1),
this.ttlConfig);
}
}
}
private void initPolicyCountersDegradoPrestazionale(Long policyDate) {
if(this.policyDegradoPrestazionaleRealtime!=null && this.policyDegradoPrestazionaleRealtime){
this.distributedPolicyDegradoPrestazionaleCounter = new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_POLICY_DEGRADO_PRESTAZIONALE_COUNTER+policyDate,
this.ttlConfig);
this.distributedPolicyDegradoPrestazionaleRequestCounter = new DatoRAtomicLong(this.redisson,
this.groupByPolicyMapIdHashCode+BuilderDatiCollezionatiDistributed.DISTRUBUITED_INTERVAL_POLICY_DEGRADO_PRESTAZIONALE_REQUEST_COUNTER+policyDate,
this.ttlConfig);
}
}
@Override
protected void resetPolicyCounterForDate(Date date) {
if(this.initialized) {
// Pre-check senza semaforo (fast path): se l'intervallo non è cambiato, non serve acquisire il lock
long policyDate = date.getTime();
long actualSuper = super.policyDate!=null ? super.policyDate.getTime() : -1;
if(actualSuper==policyDate) {
this.distributedPolicyDate.ensureTTLApplied();
return;
}
boolean needEnsureTTL = false;
List<DatoRAtomicLong> toDelete = null;
SemaphoreLock slock = this.lock.acquireThrowRuntime("resetPolicyCounterForDate");
try {
// Rileggi dopo aver acquisito il lock (double-check)
actualSuper = super.policyDate!=null ? super.policyDate.getTime() : -1;
if(actualSuper!=policyDate) {
long actual = this.distributedPolicyDate.get();
if(actual<policyDate && this.distributedPolicyDate.compareAndSet(actual, policyDate)) {
// Solo 1 nodo del cluster deve entrare in questo codice, altrimenti vengono fatti destroy più volte sullo stesso contatore
// Potrà capitare che il cestino di un nodo non venga svuotato se si entra sempre sull'altro, cmq sia rimarrà 1 cestino con dei contatori di 1 intervallo.
// Non appena ci entra poi li distruggerà.
// Raccolgo i contatori da eliminare (verranno cancellati fuori dal semaforo)
if(!this.cestinoPolicyCounters.isEmpty()) {
toDelete = new ArrayList<>(this.cestinoPolicyCounters);
this.cestinoPolicyCounters.clear();
}
if(this.distributedPolicyRequestCounter!=null || this.distributedPolicyDenyRequestCounter!=null || this.distributedPolicyCounter!=null) {
// conservo precedenti contatori
if(this.distributedPolicyRequestCounter!=null) {
this.cestinoPolicyCounters.add(this.distributedPolicyRequestCounter);
}
if(this.distributedPolicyDenyRequestCounter!=null) {
this.cestinoPolicyCounters.add(this.distributedPolicyDenyRequestCounter);
}
if(this.distributedPolicyCounter!=null) {
this.cestinoPolicyCounters.add(this.distributedPolicyCounter);
}
}
}
else {
// Se compareAndSet fallisce, il contatore esiste già (creato da altro nodo).
// L'ensureTTLApplied viene eseguito fuori dal semaforo per ridurre la contesa:
// è idempotente e sicuro da eseguire in parallelo da più thread.
needEnsureTTL = true;
}
// Serve per inizializzare i nuovi riferimenti ai contatori
initPolicyCounters(date.getTime());
// Serve per aggiornare la copia in ram del nodo in cui non si e' entrati nell'if precedente
super.resetPolicyCounterForDate(date);
}
else {
needEnsureTTL = true;
}
}finally {
this.lock.release(slock, "resetPolicyCounterForDate");
}
// Operazioni fuori dal semaforo: delete idempotenti e ensureTTL
if(toDelete != null) {
for (DatoRAtomicLong iAtomicLong : toDelete) {
iAtomicLong.delete();
}
}
if(needEnsureTTL) {
this.distributedPolicyDate.ensureTTLApplied();
}
}
else {
super.resetPolicyCounterForDate(date);
}
}
@Override
protected void resetPolicyCounterForDateDegradoPrestazionale(Date date) {
if(this.initialized) {
// Pre-check senza semaforo (fast path): se l'intervallo non è cambiato, non serve acquisire il lock
long policyDate = date.getTime();
long actualSuper = super.policyDegradoPrestazionaleDate!=null ? super.policyDegradoPrestazionaleDate.getTime() : -1;
if(actualSuper==policyDate) {
this.distributedPolicyDegradoPrestazionaleDate.ensureTTLApplied();
return;
}
boolean needEnsureTTL = false;
List<DatoRAtomicLong> toDelete = null;
SemaphoreLock slock = this.lock.acquireThrowRuntime("resetPolicyCounterForDateDegradoPrestazionale");
try {
// Rileggi dopo aver acquisito il lock (double-check)
actualSuper = super.policyDegradoPrestazionaleDate!=null ? super.policyDegradoPrestazionaleDate.getTime() : -1;
if(actualSuper!=policyDate) {
long actual = this.distributedPolicyDate.get();
if(actual<policyDate && this.distributedPolicyDegradoPrestazionaleDate.compareAndSet(actual, policyDate)) {
// Solo 1 nodo del cluster deve entrare in questo codice, altrimenti vengono fatti destroy più volte sullo stesso contatore
// Potrà capitare che il cestino di un nodo non venga svuotato se si entra sempre sull'altro, cmq sia rimarrà 1 cestino con dei contatori di 1 intervallo.
// Non appena ci entra poi li distruggerà.
// Raccolgo i contatori da eliminare (verranno cancellati fuori dal semaforo)
if(!this.cestinoPolicyCountersDegradoPrestazionale.isEmpty()) {
toDelete = new ArrayList<>(this.cestinoPolicyCountersDegradoPrestazionale);
this.cestinoPolicyCountersDegradoPrestazionale.clear();
}
if(this.distributedPolicyRequestCounter!=null || this.distributedPolicyDenyRequestCounter!=null || this.distributedPolicyCounter!=null) {
// conservo precedenti contatori
if(this.distributedPolicyDegradoPrestazionaleCounter!=null) {
this.cestinoPolicyCountersDegradoPrestazionale.add(this.distributedPolicyDegradoPrestazionaleCounter);
}
if(this.distributedPolicyDegradoPrestazionaleRequestCounter!=null) {
this.cestinoPolicyCountersDegradoPrestazionale.add(this.distributedPolicyDegradoPrestazionaleRequestCounter);
}
}
}
else {
// Se compareAndSet fallisce, il contatore esiste già (creato da altro nodo).
// L'ensureTTLApplied viene eseguito fuori dal semaforo per ridurre la contesa:
// è idempotente e sicuro da eseguire in parallelo da più thread.
needEnsureTTL = true;
}
// Serve per inizializzare i nuovi riferimenti ai contatori
initPolicyCountersDegradoPrestazionale(policyDate);
// Serve per aggiornare la copia in ram del nodo in cui non si e' entrati nell'if precedente
super.resetPolicyCounterForDateDegradoPrestazionale(date);
}
else {
needEnsureTTL = true;
}
}finally {
this.lock.release(slock, "resetPolicyCounterForDateDegradoPrestazionale");
}
// Operazioni fuori dal semaforo: delete idempotenti e ensureTTL
if(toDelete != null) {
for (DatoRAtomicLong iAtomicLong : toDelete) {
iAtomicLong.delete();
}
}
if(needEnsureTTL) {
this.distributedPolicyDegradoPrestazionaleDate.ensureTTLApplied();
}
}
else {
super.resetPolicyCounterForDateDegradoPrestazionale(date);
}
}
@Override
public void resetCounters(Date updatePolicyDate) {
super.resetCounters(updatePolicyDate);
if(updatePolicyDate!=null) {
this.distributedUpdatePolicyDate.set(updatePolicyDate.getTime());
}
if (this.distributedPolicyDenyRequestCounter != null) {
this.distributedPolicyDenyRequestCounter.set(0);
}
if (this.distributedPolicyRequestCounter != null) {
this.distributedPolicyRequestCounter.set(0l);
}
if (this.distributedPolicyCounter != null) {
this.distributedPolicyCounter.set(0l);
}
if (this.distributedPolicyDegradoPrestazionaleRequestCounter != null) {
this.distributedPolicyDegradoPrestazionaleRequestCounter.set(0l);
}
if (this.distributedPolicyDegradoPrestazionaleCounter != null) {
this.distributedPolicyDegradoPrestazionaleCounter.set(0l);
}
}
/**
* Verifica se l'intervallo delle richieste simultanee è cambiato (per ForCheck).
* Se cambiato, crea un nuovo contatore con il nuovo timestamp e mette il vecchio nel cestino.
*/
private void checkActiveRequestCounterIntervalChangeForCheck() {
if(this.distributedActiveRequestCounterDate == null || this.distributedActiveRequestCounterForCheck == null) {
return;
}
// Pre-check locale: calcolaIntervalloCorrente() e' una funzione pura (solo CPU, nessun I/O)
long currentIntervalStart = ActiveRequestDistributedIntervalManager.calcolaIntervalloCorrente(this.richiesteSimultaneeIntervalloSecondi);
if(currentIntervalStart == this.lastCheckedIntervalStartForCheck) {
return; // Nessun round-trip a Redis
}
// L'intervallo potrebbe essere cambiato, procedi con verifica distribuita
List<DatoRAtomicLong> toDelete = null;
SemaphoreLock slock = this.lock.acquireThrowRuntime("checkActiveRequestCounterIntervalChangeForCheck");
try {
long distributedDate = this.distributedActiveRequestCounterDate.get();
if(ActiveRequestDistributedIntervalManager.isIntervalloCambiato(this.richiesteSimultaneeIntervalloSecondi, distributedDate)) {
// Prova ad aggiornare la data
if(this.distributedActiveRequestCounterDate.compareAndSet(distributedDate, currentIntervalStart)) {
// Raccolgo i contatori da eliminare (verranno cancellati fuori dal semaforo)
if(!this.cestinoActiveRequestCounters.isEmpty()) {
toDelete = new ArrayList<>(this.cestinoActiveRequestCounters);
this.cestinoActiveRequestCounters.clear();
}
// Metti il vecchio contatore nel cestino
this.cestinoActiveRequestCounters.add(this.distributedActiveRequestCounterForCheck);
// Crea il nuovo contatore con il nuovo timestamp
this.distributedActiveRequestCounterForCheck = initActiveRequestCounters(currentIntervalStart);
// Aggiorna cache locale
this.lastKnownActiveRequestIntervalDate = currentIntervalStart;
getLogControlloTraffico().debug(
"[Redis] ForCheck CAS-WINNER policy={}: intervallo {} -> {} (old counter nel cestino, cestino.size={}, toDelete={})",
this.groupByPolicyMapIdHashCode, distributedDate, currentIntervalStart,
this.cestinoActiveRequestCounters.size(), (toDelete!=null ? toDelete.size() : 0));
} else {
// Un altro thread ha già aggiornato, leggi il nuovo valore e aggiorna il contatore
Long newDate = this.distributedActiveRequestCounterDate.get();
this.distributedActiveRequestCounterForCheck = initActiveRequestCounters(newDate);
this.lastKnownActiveRequestIntervalDate = newDate;
getLogControlloTraffico().debug(
"[Redis] ForCheck CAS-LOSER policy={}: aggiornato riferimento a intervallo {}",
this.groupByPolicyMapIdHashCode, newDate);
}
} else {
// L'intervallo distribuito è già stato aggiornato da un altro nodo (isIntervalloCambiato==false).
// Verifica se il riferimento locale è stale (punta ancora al vecchio intervallo).
if(distributedDate > 0 && distributedDate != this.lastKnownActiveRequestIntervalDate) {
this.distributedActiveRequestCounterForCheck = initActiveRequestCounters(distributedDate);
this.lastKnownActiveRequestIntervalDate = distributedDate;
getLogControlloTraffico().debug(
"[Redis] ForCheck STALE-FIX policy={}: aggiornato riferimento stale a intervallo {}",
this.groupByPolicyMapIdHashCode, distributedDate);
}
}
// Aggiorna il pre-check locale: l'intervallo e' stato verificato
this.lastCheckedIntervalStartForCheck = currentIntervalStart;
} finally {
this.lock.release(slock, "checkActiveRequestCounterIntervalChangeForCheck");
}
// Delete fuori dal semaforo: operazione idempotente, non impatta la correttezza
if(toDelete != null) {
for (DatoRAtomicLong counter : toDelete) {
/**System.out.println("DESTROY ACTIVE ["+counter.getName()+"]");*/
counter.delete();
}
}
}
/**
* Verifica se l'intervallo delle richieste è cambiato (per ForStats).
* Se cambiato, crea un nuovo contatore con il nuovo timestamp e mette il vecchio nel cestino.
*/
private void checkActiveRequestCounterIntervalChangeForStats() {
if(this.distributedActiveRequestCounterDate == null || this.distributedActiveRequestCounterForStats == null) {
return;
}
// Pre-check locale: calcolaIntervalloCorrente() e' una funzione pura (solo CPU, nessun I/O)
long currentIntervalStart = ActiveRequestDistributedIntervalManager.calcolaIntervalloCorrente(this.richiesteSimultaneeIntervalloSecondi);
if(currentIntervalStart == this.lastCheckedIntervalStartForStats) {
return; // Nessun round-trip a Redis
}
// L'intervallo potrebbe essere cambiato, procedi con verifica distribuita
List<DatoRAtomicLong> toDelete = null;
SemaphoreLock slock = this.lock.acquireThrowRuntime("checkActiveRequestCounterIntervalChangeForStats");
try {
long distributedDate = this.distributedActiveRequestCounterDate.get();
if(ActiveRequestDistributedIntervalManager.isIntervalloCambiato(this.richiesteSimultaneeIntervalloSecondi, distributedDate)) {
// Prova ad aggiornare la data
if(this.distributedActiveRequestCounterDate.compareAndSet(distributedDate, currentIntervalStart)) {
// Raccolgo i contatori da eliminare (verranno cancellati fuori dal semaforo)
if(!this.cestinoActiveRequestCounters.isEmpty()) {
toDelete = new ArrayList<>(this.cestinoActiveRequestCounters);
this.cestinoActiveRequestCounters.clear();
}
// Metti il vecchio contatore nel cestino
this.cestinoActiveRequestCounters.add(this.distributedActiveRequestCounterForStats);
// Crea il nuovo contatore con il nuovo timestamp
this.distributedActiveRequestCounterForStats = initActiveRequestCounters(currentIntervalStart);
// Aggiorna cache locale
this.lastKnownActiveRequestIntervalDate = currentIntervalStart;
getLogControlloTraffico().debug(
"[Redis] ForStats CAS-WINNER policy={}: intervallo {} -> {} (old counter nel cestino, cestino.size={}, toDelete={})",
this.groupByPolicyMapIdHashCode, distributedDate, currentIntervalStart,
this.cestinoActiveRequestCounters.size(), (toDelete!=null ? toDelete.size() : 0));
} else {
// Un altro thread ha già aggiornato, leggi il nuovo valore e aggiorna il contatore
Long newDate = this.distributedActiveRequestCounterDate.get();
this.distributedActiveRequestCounterForStats = initActiveRequestCounters(newDate);
this.lastKnownActiveRequestIntervalDate = newDate;
getLogControlloTraffico().debug(
"[Redis] ForStats CAS-LOSER policy={}: aggiornato riferimento a intervallo {}",
this.groupByPolicyMapIdHashCode, newDate);
}
} else {
// L'intervallo distribuito è già stato aggiornato da un altro nodo (isIntervalloCambiato==false).
// Verifica se il riferimento locale è stale (punta ancora al vecchio intervallo).
if(distributedDate > 0 && distributedDate != this.lastKnownActiveRequestIntervalDate) {
this.distributedActiveRequestCounterForStats = initActiveRequestCounters(distributedDate);
this.lastKnownActiveRequestIntervalDate = distributedDate;
getLogControlloTraffico().debug(
"[Redis] ForStats STALE-FIX policy={}: aggiornato riferimento stale a intervallo {}",
this.groupByPolicyMapIdHashCode, distributedDate);
}
}
// Aggiorna il pre-check locale: l'intervallo e' stato verificato
this.lastCheckedIntervalStartForStats = currentIntervalStart;
} finally {
this.lock.release(slock, "checkActiveRequestCounterIntervalChangeForStats");
}
// Delete fuori dal semaforo: operazione idempotente, non impatta la correttezza
if(toDelete != null) {
for (DatoRAtomicLong counter : toDelete) {
/**System.out.println("DESTROY STAT ["+counter.getName()+"]");*/
counter.delete();
}
}
}
@Override
protected void internalRegisterStartRequestIncrementActiveRequestCounter(DatiCollezionati datiCollezionatiPerPolicyVerifier, org.openspcoop2.utils.Map<Object> ctx) {
if(this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee){
// Verifica se l'intervallo è cambiato (solo se la gestione a intervalli è abilitata)
if(this.richiesteSimultaneeIntervalloSecondi > 0) {
checkActiveRequestCounterIntervalChangeForCheck();
}
if(datiCollezionatiPerPolicyVerifier!=null) {
super.activeRequestCounter = datiCollezionatiPerPolicyVerifier.setAndGetActiveRequestCounter(this.distributedActiveRequestCounterForCheck.incrementAndGet());
}
else {
super.activeRequestCounter = this.distributedActiveRequestCounterForCheck.incrementAndGet();
}
// Salva la data dell'intervallo nel contesto DOPO l'increment
// In caso di cambio intervallo durante la richiesta, potrebbe causare valori negativi
// che sono preferibili ai positivi (negativi = permissivo, positivi = restrittivo)
saveIntervalDateInContext(ctx);
}
else {
// Verifica se l'intervallo è cambiato (solo se la gestione a intervalli è abilitata)
if(this.richiesteSimultaneeIntervalloSecondi > 0) {
checkActiveRequestCounterIntervalChangeForStats();
}
this.distributedActiveRequestCounterForStats.incrementAndGetAsync();
// Salva la data dell'intervallo nel contesto DOPO l'increment
saveIntervalDateInContext(ctx);
}
}
/**
* Salva la data dell'intervallo corrente nel contesto.
* Deve essere chiamato DOPO l'increment.
*/
private void saveIntervalDateInContext(org.openspcoop2.utils.Map<Object> ctx) {
if(ctx != null && this.richiesteSimultaneeIntervalloSecondi > 0) {
Long intervalDate = getActiveRequestCounterIntervalDate();
saveActiveRequestCounterIntervalDateInContext(ctx, intervalDate);
}
}
@Override
protected void internalUpdateDatiStartRequestApplicabileIncrementRequestCounter(DatiCollezionati datiCollezionatiPerPolicyVerifier) {
if(datiCollezionatiPerPolicyVerifier!=null) {
super.policyRequestCounter = datiCollezionatiPerPolicyVerifier.setAndGetPolicyRequestCounter(this.distributedPolicyRequestCounter.incrementAndGet());
}
else {
super.policyRequestCounter = this.distributedPolicyRequestCounter.incrementAndGet();
}
}
@Override
protected void internalRegisterEndRequestDecrementActiveRequestCounter() {
if(this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee){
// Evita valori negativi: decrementa solo se > 0
if(this.distributedActiveRequestCounterForCheck.get() > 0) {
super.activeRequestCounter = this.distributedActiveRequestCounterForCheck.decrementAndGet();
}
}
else {
// Per le statistiche, decrementa solo se > 0
// Usa getAsync per evitare un round-trip sincrono verso Redis
this.distributedActiveRequestCounterForStats.getAsync().thenAccept(v -> {
if(v != null && v > 0) {
this.distributedActiveRequestCounterForStats.decrementAndGetAsync();
}
});
}
}
@Override
protected void internalRegisterEndRequestIncrementDegradoPrestazionaleRequestCounter() {
super.policyDegradoPrestazionaleRequestCounter = this.distributedPolicyDegradoPrestazionaleRequestCounter.incrementAndGet();
}
@Override
protected void internalRegisterEndRequestIncrementDegradoPrestazionaleCounter(long latenza) {
super.policyDegradoPrestazionaleCounter = this.distributedPolicyDegradoPrestazionaleCounter.addAndGet(latenza);
}
@Override
protected void internalUpdateDatiEndRequestApplicabileIncrementRequestCounter() {
super.policyRequestCounter = this.distributedPolicyRequestCounter.incrementAndGet();
}
@Override
protected void internalUpdateDatiEndRequestApplicabileDecrementRequestCounter() {
super.policyRequestCounter = this.distributedPolicyRequestCounter.decrementAndGet();
}
@Override
protected void internalUpdateDatiEndRequestApplicabileIncrementDenyRequestCounter() {
this.distributedPolicyDenyRequestCounter.incrementAndGetAsync();
}
@Override
protected void internalUpdateDatiEndRequestApplicabileIncrementCounter(long v) {
super.policyCounter = this.distributedPolicyCounter.addAndGet(v);
}
@Override
public void destroyDatiDistribuiti() {
if(this.distributedPolicyDate!=null) {
this.distributedPolicyDate.delete();
}
if(this.distributedUpdatePolicyDate!=null) {
this.distributedUpdatePolicyDate.delete();
}
if(this.distributedPolicyRequestCounter!=null) {
this.distributedPolicyRequestCounter.delete();
}
if(this.distributedPolicyCounter!=null) {
this.distributedPolicyCounter.delete();
}
if(this.distributedPolicyDegradoPrestazionaleDate!=null) {
this.distributedPolicyDegradoPrestazionaleDate.delete();
}
if(this.distributedPolicyDegradoPrestazionaleRequestCounter!=null) {
this.distributedPolicyDegradoPrestazionaleRequestCounter.delete();
}
if(this.distributedPolicyDegradoPrestazionaleCounter!=null) {
this.distributedPolicyDegradoPrestazionaleCounter.delete();
}
if(this.distributedActiveRequestCounterForStats!=null) {
this.distributedActiveRequestCounterForStats.delete();
}
if(this.distributedActiveRequestCounterForCheck!=null) {
this.distributedActiveRequestCounterForCheck.delete();
}
if(this.distributedActiveRequestCounterDate!=null) {
this.distributedActiveRequestCounterDate.delete();
}
// Svuota il cestino dei contatori delle richieste simultanee
if(this.cestinoActiveRequestCounters!=null && !this.cestinoActiveRequestCounters.isEmpty()) {
for (DatoRAtomicLong counter : this.cestinoActiveRequestCounters) {
counter.delete();
}
this.cestinoActiveRequestCounters.clear();
}
// Svuota il cestino dei contatori delle policy (intervalli precedenti)
if(this.cestinoPolicyCounters!=null && !this.cestinoPolicyCounters.isEmpty()) {
for (DatoRAtomicLong counter : this.cestinoPolicyCounters) {
counter.delete();
}
this.cestinoPolicyCounters.clear();
}
// Svuota il cestino dei contatori del degrado prestazionale (intervalli precedenti)
if(this.cestinoPolicyCountersDegradoPrestazionale!=null && !this.cestinoPolicyCountersDegradoPrestazionale.isEmpty()) {
for (DatoRAtomicLong counter : this.cestinoPolicyCountersDegradoPrestazionale) {
counter.delete();
}
this.cestinoPolicyCountersDegradoPrestazionale.clear();
}
if(this.distributedPolicyDenyRequestCounter!=null) {
this.distributedPolicyDenyRequestCounter.delete();
}
}
// Getters necessari poichè non viene aggiornato il field nella classe padre DatiCollezionati, poichè si usa il metodo Async nel caso di informazioni statistiche
@Override
public Long getActiveRequestCounter(boolean readRemoteInfo) {
if(this.distribuitedActiveRequestCounterPolicyRichiesteSimultanee){
if(readRemoteInfo) {
if(this.richiesteSimultaneeIntervalloSecondi > 0) {
checkActiveRequestCounterIntervalChangeForCheck();
}
return this.distributedActiveRequestCounterForCheck.get();
}
else {
return super.activeRequestCounter; // nelle operazioni di incremento/decremento l'ho aggiarnato via via e quindi il check utilizzerà questa informazione nel PolicyVerifier
}
}
else {
if(this.richiesteSimultaneeIntervalloSecondi > 0) {
checkActiveRequestCounterIntervalChangeForStats();
}
return this.distributedActiveRequestCounterForStats.get();
}
}
// Getters non necessari, sono utili solo se viene richiesta una lettura del dato remoto
@Override
public Long getPolicyDenyRequestCounter(boolean readRemoteInfo) {
if(readRemoteInfo) {
if(this.distributedPolicyDenyRequestCounter!=null) {
return this.distributedPolicyDenyRequestCounter.get();
}
else {
return null;
}
}
else {
return super.getPolicyDenyRequestCounter(readRemoteInfo);
}
}
@Override
public Long getPolicyRequestCounter(boolean readRemoteInfo) {
if(readRemoteInfo) {
if(this.distributedPolicyRequestCounter!=null) {
return this.distributedPolicyRequestCounter.get();
}
else {
return null;
}
}
else {
return super.getPolicyRequestCounter(readRemoteInfo);
}
}
@Override
public Long getPolicyCounter(boolean readRemoteInfo) {
if(readRemoteInfo) {
if(this.distributedPolicyCounter!=null) {
return this.distributedPolicyCounter.get();
}
else {
return null;
}
}
else {
return super.getPolicyCounter(readRemoteInfo);
}
}
@Override
public Long getPolicyDegradoPrestazionaleRequestCounter(boolean readRemoteInfo) {
if(readRemoteInfo) {
if(this.distributedPolicyDegradoPrestazionaleRequestCounter!=null) {
return this.distributedPolicyDegradoPrestazionaleRequestCounter.get();
}
else {
return null;
}
}
else {
return super.getPolicyDegradoPrestazionaleRequestCounter(readRemoteInfo);
}
}
@Override
public Long getPolicyDegradoPrestazionaleCounter(boolean readRemoteInfo) {
if(readRemoteInfo) {
if(this.distributedPolicyDegradoPrestazionaleCounter!=null) {
return this.distributedPolicyDegradoPrestazionaleCounter.get();
}
else {
return null;
}
}
else {
return super.getPolicyDegradoPrestazionaleCounter(readRemoteInfo);
}
}
}