DatoRLongAdder.java

/*
 * GovWay - A customizable API Gateway 
 * https://govway.org
 * 
 * Copyright (c) 2005-2025 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.concurrent.CompletionStage;

import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.UtilsRuntimeException;
import org.redisson.api.RLongAdder;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;

/**
 * DatoRLongAdder
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */

public class DatoRLongAdder {

	private RedissonClient redisson;
	private String name;
	
	private RLongAdder counter;
	
	private int failover = -1;
	public void setFailover(int failover) {
		this.failover = failover;
	}
	private int failoverCheckEveryMs = -1;
	
	private Logger logControlloTraffico;
	
	public DatoRLongAdder(RedissonClient redisson, String name) {
		this.redisson = redisson;
		this.name = name;
		this.initCounter();
		OpenSPCoop2Properties op2Props = OpenSPCoop2Properties.getInstance();
		this.failover = -1; // da gestire in futuro se serve
		this.failoverCheckEveryMs = -1;
		this.logControlloTraffico = OpenSPCoop2Logger.getLoggerOpenSPCoopControlloTraffico(op2Props.isControlloTrafficoDebug());
	}
	private void initCounter() {
		this.counter = this.redisson.getLongAdder(this.name);
	}
	
	public long sum() {
		RLongAdderResponse r = process(RLongAdderOperation.SUM, -1, -1);
		return r!=null ? r.valueL : -1; // else non dovrebbe succedere mai
	}
	public void add(long value) {
		process(RLongAdderOperation.ADD, value, -1);
	}
	public void increment() {
		process(RLongAdderOperation.INCREMENT, -1, -1);
	}
	public void decrement() {
		process(RLongAdderOperation.DECREMENT, -1, -1);
	}
	public void reset() {
		process(RLongAdderOperation.RESET, -1, -1);
	}
	public void destroy() {
		process(RLongAdderOperation.DESTROY, -1, -1);
	}
	
	private RLongAdderResponse process(RLongAdderOperation op, long arg1, long arg2) {
		String prefix = "[Redis-RAtomicLong-"+this.name+" operation:"+op+"] ";
		if(this.failover>0) {
			return processFailOver(prefix, op, arg1, arg2);
		}
		else {
			return operation(prefix, op, arg1, arg2);
		}
	}
	private RLongAdderResponse processFailOver(String prefix, RLongAdderOperation op, long arg1, long arg2) {
		boolean success = false;
		Exception eFinal = null; // capire l'eccezione
		RLongAdderResponse v = null;
		for (int i = 0; i < this.failover; i++) {
			try {
				if(i>0 && this.failoverCheckEveryMs>0) {
					Utilities.sleep(this.failoverCheckEveryMs);
					initCounter();
				}
				v = operation(prefix, op, arg1, arg2);
				success=true;
				break;
			} catch (Exception e) {
				eFinal = e;
				if(i==0) {
					this.logControlloTraffico.error(prefix+"rilevato contatore distrutto (verrà riprovata la creazione): "+e.getMessage(),e);
				}
				else {
					this.logControlloTraffico.error(prefix+"il tenativo i="+i+" di ricreare il contatore è fallito: "+e.getMessage(),e);
				}
			}
		}
		if(!success) {
			throwDistributedObjectDestroyedException(prefix, eFinal);
		}
		return v;
	}
	private void throwDistributedObjectDestroyedException(String prefix, Exception eFinal) {
		String msg = prefix+"tutti i tentativi di ricreare il contatore sono falliti";
		this.logControlloTraffico.error(msg);
		if(eFinal!=null) {
			throw new UtilsRuntimeException(eFinal);
		}
		else {
			throw new UtilsRuntimeException("tutti i tentativi di ricreare il contatore sono falliti"); // l'eccezione eFinal esiste
		}
	}
	
	private RLongAdderResponse operation(String prefix, RLongAdderOperation op, long arg1, long arg2){
		switch (op) {
		case SUM:
			return new RLongAdderResponse(this.counter.sum());
		case ADD:
			this.counter.add(arg1);
			return null;
		case INCREMENT:
			this.counter.increment();
			return null;
		case DECREMENT:
			this.counter.decrement();
			return null;
		case RESET:
			this.counter.reset();
			return null;
		case DESTROY:
			try {
				this.counter.destroy();
			}catch(Throwable e) {
				this.logControlloTraffico.error(prefix+"delete non riuscito: "+e.getMessage(),e);
				throw e;
			}
			return null;		
		}
		return null;
	}
}

enum RLongAdderOperation {
	SUM,
	ADD, INCREMENT, DECREMENT,
	RESET,
	DESTROY
}

class RLongAdderResponse{
	RLongAdderResponse(long l){
		this.valueL = l;
	}
	RLongAdderResponse(boolean b){
		this.valueB = b;
	}
	RLongAdderResponse(CompletionStage<Long> v){
		this.valueAsync = v;
	}
	long valueL;	
	boolean valueB;
	CompletionStage<Long> valueAsync;
}