182 lines
5.7 KiB
Java
182 lines
5.7 KiB
Java
/**
|
|
*
|
|
*/
|
|
package org.gcube.accounting.persistence;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import org.gcube.accounting.aggregation.scheduler.AggregationScheduler;
|
|
import org.gcube.accounting.datamodel.SingleUsageRecord;
|
|
import org.gcube.accounting.datamodel.UsageRecord;
|
|
import org.gcube.accounting.exception.InvalidValueException;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
|
*/
|
|
public abstract class AccountingPersistenceBackend {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(AccountingPersistenceBackend.class);
|
|
|
|
protected FallbackPersistenceBackend fallbackPersistence;
|
|
protected AggregationScheduler aggregationScheduler;
|
|
|
|
protected AccountingPersistenceBackendMonitor accountingPersistenceBackendMonitor;
|
|
|
|
/**
|
|
* Pool for thread execution
|
|
*/
|
|
private ExecutorService pool;
|
|
|
|
protected AccountingPersistenceBackend(){
|
|
this.pool = Executors.newCachedThreadPool();
|
|
if(!(this instanceof FallbackPersistenceBackend)){
|
|
this.accountingPersistenceBackendMonitor = new AccountingPersistenceBackendMonitor(this);
|
|
}
|
|
}
|
|
|
|
protected AccountingPersistenceBackend(FallbackPersistenceBackend fallback, AggregationScheduler aggregationScheduler){
|
|
this();
|
|
this.fallbackPersistence = fallback;
|
|
this.aggregationScheduler = aggregationScheduler;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return the fallbackPersistence
|
|
*/
|
|
public FallbackPersistenceBackend getFallbackPersistence() {
|
|
return fallbackPersistence;
|
|
}
|
|
|
|
/**
|
|
* @param fallback the fallback to set
|
|
*/
|
|
protected void setFallback(FallbackPersistenceBackend fallback) {
|
|
this.fallbackPersistence = fallback;
|
|
}
|
|
|
|
/**
|
|
* @return the aggregationScheduler
|
|
*/
|
|
public AggregationScheduler getAggregationScheduler() {
|
|
return aggregationScheduler;
|
|
}
|
|
|
|
/**
|
|
* @param aggregationScheduler the aggregationScheduler to set
|
|
*/
|
|
protected void setAggregationScheduler(AggregationScheduler aggregationScheduler) {
|
|
this.aggregationScheduler = aggregationScheduler;
|
|
}
|
|
|
|
/**
|
|
* Prepare the connection to persistence.
|
|
* This method must be used by implementation class to open
|
|
* the connection with the persistence storage, DB, file etc.
|
|
* @param configuration The configuration to create the connection
|
|
* @throws Exception if fails
|
|
*/
|
|
protected abstract void prepareConnection(AccountingPersistenceConfiguration configuration) throws Exception;
|
|
|
|
/**
|
|
* This method contains the code to save the {@link #UsageRecord}
|
|
*
|
|
*/
|
|
protected abstract void reallyAccount(UsageRecord usageRecords) throws Exception;
|
|
|
|
protected void accountWithFallback(UsageRecord... usageRecords) {
|
|
String persistenceName = this.getClass().getSimpleName();
|
|
logger.trace("Going to account {} using {} : {}", Arrays.toString(usageRecords), persistenceName, this);
|
|
for(UsageRecord usageRecord : usageRecords){
|
|
try {
|
|
logger.trace("Going to account {} using {} : {}", usageRecord, persistenceName, this);
|
|
this.reallyAccount(usageRecord);
|
|
logger.debug("{} accounted succesfully from {}.", usageRecord.toString(), persistenceName);
|
|
} catch (Exception e) {
|
|
try {
|
|
String fallabackPersistenceName = FallbackPersistenceBackend.class.getSimpleName();
|
|
logger.error("{} was not accounted succesfully from {}. Trying to use {}.",
|
|
usageRecord.toString(), persistenceName, fallabackPersistenceName, e);
|
|
fallbackPersistence.reallyAccount(usageRecord);
|
|
logger.debug("{} accounted succesfully from {}",
|
|
usageRecord.toString(), fallabackPersistenceName);
|
|
}catch(Exception ex){
|
|
logger.error("{} was not accounted at all", usageRecord.toString(), e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
protected void validateAccountAggregate(final SingleUsageRecord usageRecord, boolean validate, boolean aggregate){
|
|
try {
|
|
logger.debug("Received record to account : {}", usageRecord);
|
|
if(validate){
|
|
usageRecord.validate();
|
|
logger.trace("Record {} valid", usageRecord);
|
|
}
|
|
if(aggregate){
|
|
final AccountingPersistenceBackend persistence = this;
|
|
aggregationScheduler.aggregate(usageRecord, new AccountingPersistenceExecutor(){
|
|
|
|
@Override
|
|
public void persist(UsageRecord... usageRecords) throws Exception {
|
|
persistence.accountWithFallback(usageRecords);
|
|
}
|
|
|
|
});
|
|
}else{
|
|
this.accountWithFallback(usageRecord);
|
|
}
|
|
|
|
} catch (InvalidValueException e) {
|
|
logger.error("Error validating UsageRecord", e);
|
|
} catch (Exception e) {
|
|
logger.error("Error accounting UsageRecord", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Persist the {@link #UsageRecord}.
|
|
* The Record is validated first, then accounted, in a separated thread.
|
|
* So that the program can continue the execution.
|
|
* If the persistence fails the class write that the record in a local file
|
|
* so that the {@link #UsageRecord} can be recorder later.
|
|
* @param usageRecord the {@link #UsageRecord} to persist
|
|
* @throws InvalidValueException if the Record Validation Fails
|
|
*/
|
|
public void account(final SingleUsageRecord usageRecord) throws InvalidValueException{
|
|
Runnable runnable = new Runnable(){
|
|
@Override
|
|
public void run(){
|
|
validateAccountAggregate(usageRecord, true, true);
|
|
}
|
|
};
|
|
pool.execute(runnable);
|
|
|
|
}
|
|
|
|
public void flush(long timeout, TimeUnit timeUnit) throws Exception {
|
|
pool.awaitTermination(timeout, timeUnit);
|
|
|
|
final AccountingPersistenceBackend persistence = this;
|
|
aggregationScheduler.flush(new AccountingPersistenceExecutor(){
|
|
|
|
@Override
|
|
public void persist(UsageRecord... usageRecords) throws Exception {
|
|
persistence.accountWithFallback(usageRecords);
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
public abstract void close() throws Exception;
|
|
|
|
}
|