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:
parent
b9ef37db2b
commit
8f15b524dd
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue