refs #200: Create accouting-lib library

https://support.d4science.org/issues/200
Implementing Aggregation Strategy

git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/accounting/accounting-lib@115539 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Luca Frosini 2015-06-25 12:30:50 +00:00
parent b9ef37db2b
commit 8f15b524dd
9 changed files with 267 additions and 34 deletions

View File

@ -28,6 +28,10 @@ public abstract class AggregationStrategy<T extends AggregatedUsageRecord<T, B>,
this.aggregationField.add(BasicUsageRecord.SCOPE);
this.aggregationField.add(BasicUsageRecord.OPERATION_RESULT);
}
public T getAggregatedUsageRecord(){
return t;
}
protected String commonFieldHash(B record) {
try {
@ -64,7 +68,7 @@ public abstract class AggregationStrategy<T extends AggregatedUsageRecord<T, B>,
public T aggregate(B record) throws NotAggregatableRecordsExceptions {
try{
if(isAggregable(record)){
if(!isAggregable(record)){
throw new NotAggregatableRecordsExceptions("The Record provided as argument has different values for field wich must be common to be aggragatable");
}
@ -82,8 +86,11 @@ public abstract class AggregationStrategy<T extends AggregatedUsageRecord<T, B>,
((BasicUsageRecord) t).setEndTime(convertedEndTime);
}
Calendar newCreationTime = Calendar.getInstance();
t = reallyAggregate(convertedRecord);
t.setCreationTime(newCreationTime);
return t;
}catch(NotAggregatableRecordsExceptions e){
throw e;

View File

@ -0,0 +1,72 @@
/**
*
*/
package org.gcube.accounting.datamodel;
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
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 class TestUsageRecord {
private static final Logger logger = LoggerFactory.getLogger(TestUsageRecord.class);
public final static String TEST_CONSUMER_ID = "name.surname";
public final static String TEST_SCOPE = "/infrastructure/vo";
public final static String TEST_SERVICE_CLASS = "TestServiceClass";
public final static String TEST_SERVICE_NAME = "TestServiceName";
public final static String TEST_REF_HOST = "localhost";
public final static String TEST_REF_VM = "local";
public final static String TEST_PROPERTY_NAME = "TestPropertyName";
public final static String TEST_PROPERTY_VALUE = "TestPropertyValue";
private final static long MIN = 60;
private final static long MAX = 1000;
/**
* Generate A Random long in a range between min and max.
* This function is internally used to set random duration.
* @return the generated random long
*/
public static long generateRandomLong(long min, long max){
return min + (int)(Math.random() * ((max - min) + 1));
}
/**
* Create a valid SingleUsageRecord
* @return the created UsageRecord
*/
public static SingleUsageRecord createTestUsageRecord() {
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
try {
serviceUsageRecord.setConsumerId(TEST_CONSUMER_ID);
serviceUsageRecord.setScope(TEST_SCOPE);
serviceUsageRecord.setOperationResult(OperationResult.SUCCESS);
serviceUsageRecord.setServiceClass(TEST_SERVICE_CLASS);
serviceUsageRecord.setServiceName(TEST_SERVICE_NAME);
serviceUsageRecord.setRefHost(TEST_REF_HOST);
serviceUsageRecord.setRefVM(TEST_REF_VM);
serviceUsageRecord.setDuration(generateRandomLong(MIN, MAX));
serviceUsageRecord.setResourceProperty(TEST_PROPERTY_NAME, TEST_PROPERTY_VALUE);
} catch (InvalidValueException e) {
logger.error(" ------ You SHOULD NOT SEE THIS MESSAGE. Error Creating a test Usage Record", e.getCause());
}
return serviceUsageRecord;
}
}

View File

@ -57,6 +57,7 @@ public class ServiceUsageRecord extends org.gcube.accounting.datamodel.implement
this.setMinInvocationTime(duration);
this.setMaxInvocationTime(duration);
Calendar creationTime = record.getCreationTime();
this.setCreationTime(creationTime);
this.setStartTime(creationTime);
this.setEndTime(creationTime);
init();

View File

@ -18,7 +18,7 @@ public class ServiceUsageRecordAggregationStrategy extends AggregationStrategy<S
*/
public ServiceUsageRecordAggregationStrategy(ServiceUsageRecord serviceUsageRecord) {
super(serviceUsageRecord);
this.aggregationField.add(ServiceUsageRecord.CALLER_IP);
//this.aggregationField.add(ServiceUsageRecord.CALLER_IP);
this.aggregationField.add(ServiceUsageRecord.REF_HOST);
this.aggregationField.add(ServiceUsageRecord.REF_VM);
this.aggregationField.add(ServiceUsageRecord.SERVICE_CLASS);

View File

@ -1,7 +1,10 @@
package org.gcube.accounting.messaging;
import org.gcube.accounting.datamodel.RawUsageRecord;
import org.gcube.accounting.exception.InvalidValueException;
import org.gcube.accounting.persistence.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class has been created for backward compatibility.
@ -11,6 +14,10 @@ import org.gcube.accounting.persistence.Persistence;
@Deprecated
public class ResourceAccounting {
private static final Logger logger = LoggerFactory.getLogger(ResourceAccounting.class);
@Deprecated
protected Persistence persistence;
@Deprecated
@ -20,7 +27,11 @@ public class ResourceAccounting {
@Deprecated
public void sendAccountingMessage(RawUsageRecord message){
persistence.account(message);
try {
persistence.account(message);
} catch (InvalidValueException e) {
logger.error("The Record you are going to account is not valid", e.getCause());
}
}

View File

@ -9,8 +9,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.gcube.accounting.datamodel.SingleUsageRecord;
import org.gcube.accounting.datamodel.TestUsageRecord;
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;
@ -73,7 +73,7 @@ public abstract class Persistence {
if(persistence==null){
persistence = fallback;
}
persistence.account(createTestUsageRecord());
persistence.account(TestUsageRecord.createTestUsageRecord());
} catch(Exception e){
logger.error("Unable to instance a Persistence Implementation. Using fallback as default",
e.getCause());
@ -81,23 +81,6 @@ public abstract class Persistence {
}
}
public static SingleUsageRecord createTestUsageRecord(){
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
try {
serviceUsageRecord.setConsumerId("accounting");
serviceUsageRecord.setScope("/gcube/devsec");
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
*/
@ -167,13 +150,17 @@ public abstract class Persistence {
/**
* Persist the {@link #UsageRecord}.
* This method account the record in a separated thread. So that the
* program can continue the execution.
* The Record is validated first, if validation fails an
* #InvalidValueException is thrown.
* If validation success, the record is 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){
public void account(final SingleUsageRecord usageRecord) throws InvalidValueException{
usageRecord.validate();
Runnable runnable = new Runnable(){
@Override
public void run(){

View File

@ -3,7 +3,7 @@
*/
package org.gcube.accounting.datamodel;
import org.gcube.accounting.persistence.Persistence;
import org.gcube.accounting.exception.InvalidValueException;
import org.junit.Assert;
import org.junit.Test;
@ -14,8 +14,8 @@ import org.junit.Test;
public class UsageRecordTest {
@Test
public void testCompareToSameObject(){
UsageRecord usageRecord = Persistence.createTestUsageRecord();
public void testCompareToSameObject() throws InvalidValueException {
UsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
UsageRecord ur = usageRecord;
Assert.assertEquals(0, usageRecord.compareTo(ur));
Assert.assertEquals(0, ur.compareTo(usageRecord));
@ -23,7 +23,7 @@ public class UsageRecordTest {
@Test
public void testCompareToEqualsObject() throws Exception {
UsageRecord usageRecord = Persistence.createTestUsageRecord();
UsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
UsageRecord ur = BasicUsageRecord.getUsageRecord(usageRecord.getResourceProperties());
Assert.assertEquals(0, usageRecord.compareTo(ur));
Assert.assertEquals(0, ur.compareTo(usageRecord));
@ -31,7 +31,7 @@ public class UsageRecordTest {
@Test
public void testCompareToComparedAddedProperty() throws Exception {
UsageRecord usageRecord = Persistence.createTestUsageRecord();
UsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
UsageRecord ur = BasicUsageRecord.getUsageRecord(usageRecord.getResourceProperties());
for(int i=1; i<31; i++){
ur.setResourceProperty(Integer.toString(i), i);
@ -42,7 +42,7 @@ public class UsageRecordTest {
@Test
public void testCompareToDifferentForAddedProperties() throws Exception {
UsageRecord usageRecord = Persistence.createTestUsageRecord();
UsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
UsageRecord ur = BasicUsageRecord.getUsageRecord(usageRecord.getResourceProperties());
usageRecord.setResourceProperty(Integer.toString(1), 2);
ur.setResourceProperty(Integer.toString(2), 2);
@ -52,8 +52,8 @@ public class UsageRecordTest {
@Test
public void testCompareToDifferentFromCreation() throws Exception {
UsageRecord usageRecord = Persistence.createTestUsageRecord();
UsageRecord ur = Persistence.createTestUsageRecord();
UsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
UsageRecord ur = TestUsageRecord.createTestUsageRecord();
Assert.assertEquals(1, usageRecord.compareTo(ur));
Assert.assertEquals(1, ur.compareTo(usageRecord));
}

View File

@ -0,0 +1,154 @@
/**
*
*/
package org.gcube.accounting.datamodel.aggreagtion.aggregationstrategy;
import org.gcube.accounting.datamodel.TestUsageRecord;
import org.gcube.accounting.datamodel.aggregation.aggregationstrategy.ServiceUsageRecordAggregationStrategy;
import org.gcube.accounting.datamodel.implementations.ServiceUsageRecord;
import org.gcube.accounting.exception.InvalidValueException;
import org.gcube.accounting.exception.NotAggregatableRecordsExceptions;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
*
*/
public class ServiceUsageRecordAggregationStrategyTest {
private static Logger logger = LoggerFactory.getLogger(ServiceUsageRecordAggregationStrategyTest.class);
@Test
public void secondAsNotAggregated() throws InvalidValueException, NotAggregatableRecordsExceptions {
ServiceUsageRecord serviceUsageRecord = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
serviceUsageRecord.validate();
logger.debug("ServiceUsageRecord : {}", serviceUsageRecord);
org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord aggregated =
new org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord(serviceUsageRecord);
logger.debug("ServiceUsageRecord Converted to Aggregated: {}", aggregated);
aggregated.validate();
ServiceUsageRecord serviceUsageRecord2 = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
serviceUsageRecord2.validate();
logger.debug("ServiceUsageRecord 2 : {}", serviceUsageRecord2);
ServiceUsageRecordAggregationStrategy suras = new ServiceUsageRecordAggregationStrategy(aggregated);
long firstduration = serviceUsageRecord.getDuration();
long secondDuration = serviceUsageRecord2.getDuration();
suras.aggregate(serviceUsageRecord2);
logger.debug("Resulting Aggregated ServiceUsageRecord: {}", aggregated);
aggregated.validate();
Assert.assertTrue(aggregated.getDuration() == ((firstduration + secondDuration)/2));
Assert.assertTrue(aggregated.getInvocationCount() == 2);
if(firstduration >= secondDuration){
Assert.assertTrue(aggregated.getMaxInvocationTime() == firstduration);
Assert.assertTrue(aggregated.getMinInvocationTime() == secondDuration);
}else{
Assert.assertTrue(aggregated.getMaxInvocationTime() == secondDuration);
Assert.assertTrue(aggregated.getMinInvocationTime() == firstduration);
}
}
@Test
public void secondAsAggregated() throws InvalidValueException, NotAggregatableRecordsExceptions {
ServiceUsageRecord serviceUsageRecord = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
serviceUsageRecord.validate();
logger.debug("ServiceUsageRecord : {}", serviceUsageRecord);
org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord aggregated =
new org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord(serviceUsageRecord);
logger.debug("ServiceUsageRecord Converted to Aggregated: {}", aggregated);
aggregated.validate();
ServiceUsageRecord serviceUsageRecord2 = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
serviceUsageRecord2.validate();
logger.debug("ServiceUsageRecord 2 : {}", serviceUsageRecord2);
org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord converted2 =
new org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord(serviceUsageRecord2);
logger.debug("ServiceUsageRecord 2 Converted to Aggregated: {}", converted2);
converted2.validate();
ServiceUsageRecordAggregationStrategy suras = new ServiceUsageRecordAggregationStrategy(aggregated);
long firstduration = aggregated.getDuration();
long secondDuration = converted2.getDuration();
suras.aggregate(converted2);
logger.debug("Resulting Aggregated ServiceUsageRecord: {}", aggregated);
aggregated.validate();
Assert.assertTrue(aggregated.getDuration() == ((firstduration + secondDuration)/2));
Assert.assertTrue(aggregated.getInvocationCount() == 2);
if(firstduration >= secondDuration){
Assert.assertTrue(aggregated.getMaxInvocationTime() == firstduration);
Assert.assertTrue(aggregated.getMinInvocationTime() == secondDuration);
}else{
Assert.assertTrue(aggregated.getMaxInvocationTime() == secondDuration);
Assert.assertTrue(aggregated.getMinInvocationTime() == firstduration);
}
}
@Test
public void aggregationStressTest() throws InvalidValueException, NotAggregatableRecordsExceptions {
ServiceUsageRecord serviceUsageRecord = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
serviceUsageRecord.validate();
logger.debug("ServiceUsageRecord : {}", serviceUsageRecord);
org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord aggregated =
new org.gcube.accounting.datamodel.aggregation.ServiceUsageRecord(serviceUsageRecord);
logger.debug("ServiceUsageRecord Converted to Aggregated: {}", aggregated);
aggregated.validate();
ServiceUsageRecordAggregationStrategy suras = new ServiceUsageRecordAggregationStrategy(aggregated);
for(int i=2; i<1002; i++){
ServiceUsageRecord sur = (ServiceUsageRecord) TestUsageRecord.createTestUsageRecord();
sur.validate();
logger.debug("Cycle ServiceUsageRecord {}: {}", i, sur);
long minInvocationTime = aggregated.getMinInvocationTime();
long maxInvocationTime = aggregated.getMaxInvocationTime();
long oldDuration = aggregated.getDuration();
long newDuration = sur.getDuration();
suras.aggregate(sur);
logger.debug("Resulting Aggregated ServiceUsageRecord: {}", aggregated);
aggregated.validate();
Assert.assertTrue(aggregated.getDuration() == ((oldDuration + newDuration)/2));
Assert.assertTrue(aggregated.getInvocationCount() == i);
if(minInvocationTime >= newDuration){
Assert.assertTrue(aggregated.getMinInvocationTime() == newDuration);
}else{
Assert.assertTrue(aggregated.getMinInvocationTime() == minInvocationTime);
}
if(maxInvocationTime >= newDuration){
Assert.assertTrue(aggregated.getMaxInvocationTime() == maxInvocationTime);
}else{
Assert.assertTrue(aggregated.getMaxInvocationTime() == newDuration);
}
}
logger.debug("Resulting Aggregated ServiceUsageRecord: {}", aggregated);
}
}

View File

@ -7,6 +7,7 @@ import java.util.Calendar;
import java.util.GregorianCalendar;
import org.gcube.accounting.datamodel.SingleUsageRecord;
import org.gcube.accounting.datamodel.TestUsageRecord;
import org.gcube.accounting.persistence.Persistence;
import org.junit.Test;
import org.slf4j.Logger;
@ -36,7 +37,7 @@ public class PersistenceTest {
int quantity = 3000;
Calendar startTestTime = new GregorianCalendar();
for(int i=0; i< quantity; i++){
SingleUsageRecord usageRecord = Persistence.createTestUsageRecord();
SingleUsageRecord usageRecord = TestUsageRecord.createTestUsageRecord();
persistence.account(usageRecord);
}
Calendar stopTestTime = new GregorianCalendar();