207 lines
6.0 KiB
Java
207 lines
6.0 KiB
Java
/**
|
|
*
|
|
*/
|
|
package org.gcube.accounting.persistence;
|
|
|
|
import java.io.File;
|
|
import java.util.ServiceLoader;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
|
|
import org.gcube.accounting.datamodel.BasicUsageRecord;
|
|
import org.gcube.accounting.datamodel.UsageRecord;
|
|
import org.gcube.accounting.datamodel.implementations.ServiceUsageRecord;
|
|
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 Persistence {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(Persistence.class);
|
|
|
|
private static final String ACCOUTING_FALLBACK_FILENAME = "accountingFallback.log";
|
|
|
|
/**
|
|
* The singleton instance of persistence
|
|
*/
|
|
protected static Persistence persistence;
|
|
protected static FallbackPersistence fallback;
|
|
|
|
private static File file(File file) throws IllegalArgumentException {
|
|
|
|
if (file.isDirectory())
|
|
throw new IllegalArgumentException(file.getAbsolutePath() + " cannot be used in write mode because it's folder");
|
|
|
|
//create folder structure it does not exist
|
|
if (!file.getParentFile().exists())
|
|
file.getParentFile().mkdirs();
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
public synchronized static void setFallbackLocation(String path){
|
|
if(fallback == null){
|
|
if(path==null){
|
|
path = ".";
|
|
}
|
|
File file = file(new File(path, ACCOUTING_FALLBACK_FILENAME));
|
|
fallback = new FallbackPersistence(file);
|
|
}
|
|
}
|
|
|
|
protected static void init() {
|
|
setFallbackLocation(null);
|
|
try {
|
|
ServiceLoader<Persistence> serviceLoader = ServiceLoader.load(Persistence.class);
|
|
for (Persistence foundPersistence : serviceLoader) {
|
|
if(foundPersistence.getClass().isInstance(FallbackPersistence.class)){
|
|
continue;
|
|
}
|
|
try {
|
|
logger.debug(String.format("Testing %s", persistence.getClass().getSimpleName()));
|
|
foundPersistence.prepareConnection();
|
|
persistence = foundPersistence;
|
|
break;
|
|
} catch (Exception e) {
|
|
logger.debug(String.format("%s not initialized correctly. It will not be used", foundPersistence.getClass().getSimpleName()));
|
|
}
|
|
}
|
|
if(persistence==null){
|
|
persistence = fallback;
|
|
}
|
|
persistence.account(createTestUsageRecord());
|
|
} catch(Exception e){
|
|
logger.error("Unable to instance a Persistence Implementation. Using fallback as default",
|
|
e.getCause());
|
|
persistence = fallback;
|
|
}
|
|
}
|
|
|
|
public static BasicUsageRecord createTestUsageRecord(){
|
|
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
|
|
try {
|
|
serviceUsageRecord.setConsumerId("accounting");
|
|
|
|
serviceUsageRecord.setScope("/gcube/devsec");
|
|
|
|
//Calendar creationTime = new GregorianCalendar();
|
|
//Calendar startTime = new GregorianCalendar();
|
|
//Calendar endTime = new GregorianCalendar();
|
|
|
|
//serviceUsageRecord.setCreationTime(creationTime);
|
|
//usageRecord.setStartTime(startTime);
|
|
//usageRecord.setEndTime(endTime);
|
|
|
|
serviceUsageRecord.setResourceProperty("ConnectionTest", "Test");
|
|
|
|
serviceUsageRecord.setServiceClass("Accounting");
|
|
serviceUsageRecord.setServiceName("Accounting-Lib");
|
|
serviceUsageRecord.setRefHost("localhost");
|
|
serviceUsageRecord.setRefVM("local");
|
|
|
|
|
|
} catch (InvalidValueException e1) {
|
|
|
|
}
|
|
|
|
return serviceUsageRecord;
|
|
}
|
|
|
|
|
|
/**
|
|
* Pool for thread execution
|
|
*/
|
|
private ExecutorService pool;
|
|
|
|
/**
|
|
* @return the singleton instance of persistence
|
|
* @throws Exception if fails
|
|
*/
|
|
public static Persistence getInstance() {
|
|
if(persistence==null){
|
|
init();
|
|
}
|
|
return persistence;
|
|
}
|
|
|
|
protected Persistence() {
|
|
pool = Executors.newCachedThreadPool();
|
|
}
|
|
|
|
/**
|
|
* Prepare the connection to persistence.
|
|
* This method must be used by implementation class to open
|
|
* the connection with the persistence storage, DB, file etc.
|
|
* @throws Exception if fails
|
|
*/
|
|
protected abstract void prepareConnection() throws Exception;
|
|
|
|
/* *
|
|
* Prepare the connection and try to write a test record on default
|
|
* persistence and fallback persistence.
|
|
* This method should not be re-implemented from subclass.
|
|
* @throws Exception if fails
|
|
* /
|
|
public void connect() throws Exception {
|
|
persistence.prepareConnection();
|
|
persistence.account(createTestUsageRecord());
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* This method contains the code to save the {@link #UsageRecord}
|
|
*
|
|
*/
|
|
protected abstract void reallyAccount(UsageRecord usageRecord) throws Exception;
|
|
|
|
private void accountWithFallback(BasicUsageRecord usageRecord) throws Exception {
|
|
String persistenceName = getInstance().getClass().getSimpleName();
|
|
try {
|
|
//logger.debug("Going to account {} using {}", usageRecord, persistenceName);
|
|
persistence.reallyAccount(usageRecord);
|
|
logger.debug("{} accounted succesfully from {}.", usageRecord, persistenceName);
|
|
} catch (Exception e) {
|
|
String fallabackPersistenceName = fallback.getClass().getSimpleName();
|
|
try {
|
|
logger.error("{} was not accounted succesfully from {}. Trying to use {}.",
|
|
usageRecord, persistenceName, fallabackPersistenceName);
|
|
fallback.reallyAccount(usageRecord);
|
|
logger.debug("{} accounted succesfully from {}",
|
|
usageRecord, fallabackPersistenceName);
|
|
}catch(Exception ex){
|
|
logger.error("{} was not accounted at all", usageRecord);
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Persist the {@link #UsageRecord}.
|
|
* This method account the record 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
|
|
*/
|
|
public void account(final BasicUsageRecord usageRecord){
|
|
Runnable runnable = new Runnable(){
|
|
@Override
|
|
public void run(){
|
|
try {
|
|
persistence.accountWithFallback(usageRecord);
|
|
} catch (Exception e) {
|
|
logger.error("Error accouting UsageRecod", e.getCause());
|
|
}
|
|
}
|
|
};
|
|
pool.execute(runnable);
|
|
}
|
|
|
|
public abstract void close() throws Exception;
|
|
|
|
}
|