2015-06-10 17:36:50 +02:00
/ * *
*
* /
package org.gcube.accounting.datamodel ;
import java.io.Serializable ;
import java.lang.annotation.Annotation ;
import java.lang.reflect.Field ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Calendar ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Map.Entry ;
import java.util.Set ;
import java.util.UUID ;
import org.gcube.accounting.datamodel.decorators.AggregatedField ;
import org.gcube.accounting.datamodel.decorators.ComputedField ;
import org.gcube.accounting.datamodel.decorators.FieldAction ;
import org.gcube.accounting.datamodel.decorators.FieldDecorator ;
import org.gcube.accounting.datamodel.decorators.RequiredField ;
import org.gcube.accounting.datamodel.validations.annotations.NotEmpty ;
import org.gcube.accounting.datamodel.validations.annotations.ValidLong ;
import org.gcube.accounting.datamodel.validations.annotations.ValidOperationResult ;
2015-07-20 15:45:27 +02:00
import org.gcube.common.scope.api.ScopeProvider ;
2015-12-18 17:09:05 +01:00
import org.gcube.documentstore.exception.InvalidValueException ;
import org.gcube.documentstore.records.AggregatedRecord ;
import org.gcube.documentstore.records.Record ;
2015-06-10 17:36:50 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
/ * *
* @author Luca Frosini ( ISTI - CNR ) http : //www.lucafrosini.com/
*
* /
2015-12-18 17:09:05 +01:00
public abstract class BasicUsageRecord implements UsageRecord {
2015-06-10 17:36:50 +02:00
/ * *
* Generated Serial Version UID
* /
private static final long serialVersionUID = - 2060728578456796388L ;
private static Logger logger = LoggerFactory . getLogger ( BasicUsageRecord . class ) ;
@RequiredField @NotEmpty
2015-12-18 17:09:05 +01:00
private static final String ID = Record . ID ;
2015-06-10 17:36:50 +02:00
@RequiredField @NotEmpty
2015-12-18 17:09:05 +01:00
private static final String CONSUMER_ID = UsageRecord . CONSUMER_ID ;
2015-06-10 17:36:50 +02:00
@RequiredField @ValidLong
2015-12-18 17:09:05 +01:00
private static final String CREATION_TIME = Record . CREATION_TIME ;
2015-06-25 15:58:26 +02:00
2015-06-23 17:47:38 +02:00
@RequiredField @NotEmpty
2015-12-18 17:09:05 +01:00
private static final String RECORD_TYPE = Record . RECORD_TYPE ;
// TODO MOVE TO RECORD_TYPE
@Deprecated @RequiredField @NotEmpty
public static final String USAGE_RECORD_TYPE = " usageRecordType " ;
2015-06-25 17:41:20 +02:00
2015-06-23 17:47:38 +02:00
@RequiredField @NotEmpty
2015-12-18 17:09:05 +01:00
private static final String SCOPE = UsageRecord . SCOPE ;
2015-06-25 16:41:13 +02:00
2015-06-23 17:47:38 +02:00
@RequiredField @ValidOperationResult
2015-12-18 17:09:05 +01:00
private static final String OPERATION_RESULT = UsageRecord . OPERATION_RESULT ;
2015-06-23 17:47:38 +02:00
2015-06-24 17:51:46 +02:00
/** resource-specific properties */
2015-11-30 17:49:18 +01:00
protected Map < String , Comparable < ? extends Serializable > > resourceProperties ;
2015-06-24 17:51:46 +02:00
protected Map < String , List < FieldAction > > validation ;
protected Set < String > requiredFields ;
2015-07-09 15:34:31 +02:00
2015-07-01 16:40:49 +02:00
/ * *
2015-07-09 15:34:31 +02:00
* { @inheritDoc }
2015-07-01 16:40:49 +02:00
* /
2015-07-09 15:34:31 +02:00
@Override
2015-07-01 16:40:49 +02:00
public Set < String > getRequiredFields ( ) {
return requiredFields ;
}
2015-06-24 17:51:46 +02:00
protected Set < String > computedFields ;
2015-06-10 17:36:50 +02:00
2015-12-18 17:09:05 +01:00
private static final String START_TIME = AggregatedRecord . START_TIME ;
private static final String END_TIME = AggregatedRecord . END_TIME ;
private static final String OPERATION_COUNT = AggregatedUsageRecord . OPERATION_COUNT ;
2015-06-10 17:36:50 +02:00
protected Set < String > aggregatedFields ;
2015-06-24 17:51:46 +02:00
2015-07-02 11:00:10 +02:00
protected static Set < Field > getAllFields ( Class < ? > type ) {
Set < Field > fields = new HashSet < Field > ( ) ;
for ( Class < ? > c = type ; c ! = null ; c = c . getSuperclass ( ) )
fields . addAll ( Arrays . asList ( c . getDeclaredFields ( ) ) ) ;
return fields ;
}
2015-06-10 17:36:50 +02:00
protected void initializeValidation ( ) {
2015-07-13 12:55:57 +02:00
//logger.trace("Initializing Field Validators");
2015-07-02 11:00:10 +02:00
Set < Field > fields = getAllFields ( this . getClass ( ) ) ;
2015-07-01 18:09:42 +02:00
2015-06-10 17:36:50 +02:00
for ( Field field : fields ) {
2015-07-02 11:20:36 +02:00
boolean defaultAccessibility = field . isAccessible ( ) ;
2015-07-02 11:00:10 +02:00
field . setAccessible ( true ) ;
2015-06-10 17:36:50 +02:00
String keyString ;
try {
keyString = ( String ) field . get ( null ) ;
} catch ( Exception e ) {
continue ;
}
List < FieldAction > fieldValidators = new ArrayList < FieldAction > ( ) ;
validation . put ( keyString , fieldValidators ) ;
for ( Annotation annotation : field . getAnnotations ( ) ) {
if ( annotation . annotationType ( ) . isAnnotationPresent ( FieldDecorator . class ) ) {
Class < ? extends FieldAction > managedClass = ( ( FieldDecorator ) annotation . annotationType ( ) . getAnnotation ( FieldDecorator . class ) ) . managed ( ) ;
FieldAction validator ;
try {
validator = managedClass . newInstance ( ) ;
} catch ( InstantiationException | IllegalAccessException e ) {
2015-10-09 14:52:42 +02:00
logger . error ( " {} {} " , keyString , annotation , e ) ;
2015-06-10 17:36:50 +02:00
continue ;
}
fieldValidators . add ( validator ) ;
}
if ( annotation . annotationType ( ) . isAssignableFrom ( RequiredField . class ) ) {
requiredFields . add ( keyString ) ;
}
if ( annotation . annotationType ( ) . isAssignableFrom ( AggregatedField . class ) ) {
aggregatedFields . add ( keyString ) ;
}
if ( annotation . annotationType ( ) . isAssignableFrom ( ComputedField . class ) ) {
computedFields . add ( keyString ) ;
}
}
2015-07-02 11:20:36 +02:00
field . setAccessible ( defaultAccessibility ) ;
2015-06-10 17:36:50 +02:00
}
2015-07-13 12:55:57 +02:00
/ *
2015-07-02 11:00:10 +02:00
logger . trace ( " Required Fields {} " , requiredFields ) ;
logger . trace ( " Aggregated Fields {} " , aggregatedFields ) ;
logger . trace ( " Computed Fields {} " , computedFields ) ;
2015-07-13 12:55:57 +02:00
* /
2015-06-10 17:36:50 +02:00
}
2015-12-18 17:09:05 +01:00
protected void cleanExtraFields ( ) {
Set < String > neededFields = this . requiredFields ;
neededFields . addAll ( this . aggregatedFields ) ;
Set < String > keysToRemove = new HashSet < String > ( ) ;
Set < String > propertyKeys = this . resourceProperties . keySet ( ) ;
for ( String propertyName : propertyKeys ) {
if ( ! neededFields . contains ( propertyName ) ) {
keysToRemove . add ( propertyName ) ;
}
}
for ( String keyToRemove : keysToRemove ) {
this . resourceProperties . remove ( keyToRemove ) ;
}
}
2015-06-10 17:36:50 +02:00
/ * *
* Initialize variable
* /
2015-06-26 15:50:39 +02:00
private void init ( ) {
2015-06-10 17:36:50 +02:00
this . validation = new HashMap < String , List < FieldAction > > ( ) ;
this . requiredFields = new HashSet < String > ( ) ;
2015-06-15 17:01:56 +02:00
this . aggregatedFields = new HashSet < String > ( ) ;
this . computedFields = new HashSet < String > ( ) ;
2015-11-30 17:49:18 +01:00
this . resourceProperties = new HashMap < String , Comparable < ? extends Serializable > > ( ) ;
2015-06-10 17:36:50 +02:00
initializeValidation ( ) ;
2015-07-20 15:45:27 +02:00
try {
2015-07-20 17:02:43 +02:00
this . setScope ( ScopeProvider . instance . get ( ) ) ;
} catch ( Exception e ) {
2015-07-20 15:45:27 +02:00
logger . warn ( " Unable to automaticcally set the scope using scope provider. The record will not be valid if the scope will not be explicitly set. " ) ;
}
2015-06-10 17:36:50 +02:00
}
public BasicUsageRecord ( ) {
init ( ) ;
this . resourceProperties . put ( ID , UUID . randomUUID ( ) . toString ( ) ) ;
2015-12-18 17:09:05 +01:00
this . setRecordType ( ) ;
2015-06-10 17:36:50 +02:00
Calendar calendar = Calendar . getInstance ( ) ;
this . resourceProperties . put ( CREATION_TIME , calendar . getTimeInMillis ( ) ) ;
}
2015-11-30 17:49:18 +01:00
public BasicUsageRecord ( Map < String , Comparable < ? extends Serializable > > properties ) throws InvalidValueException {
2015-06-10 17:36:50 +02:00
init ( ) ;
setResourceProperties ( properties ) ;
2015-12-18 17:09:05 +01:00
if ( this instanceof AggregatedUsageRecord ) {
this . resourceProperties . put ( AggregatedUsageRecord . AGGREGATED , true ) ;
cleanExtraFields ( ) ;
}
}
@Deprecated
public String getUsageRecordType ( ) {
return getRecordType ( ) ;
2015-06-10 17:36:50 +02:00
}
2015-07-29 14:41:28 +02:00
@Override
2015-12-18 17:09:05 +01:00
public String getRecordType ( ) {
return ( String ) this . resourceProperties . get ( RECORD_TYPE ) ;
2015-07-29 14:41:28 +02:00
}
protected abstract String giveMeUsageRecordType ( ) ;
2015-12-18 17:09:05 +01:00
@Deprecated
2015-07-29 14:41:28 +02:00
protected void setUsageRecordType ( ) {
2015-12-18 17:09:05 +01:00
setRecordType ( ) ;
}
protected void setRecordType ( ) {
this . resourceProperties . put ( RECORD_TYPE , this . giveMeUsageRecordType ( ) ) ;
2015-07-29 14:41:28 +02:00
this . resourceProperties . put ( USAGE_RECORD_TYPE , this . giveMeUsageRecordType ( ) ) ;
}
2015-06-10 17:36:50 +02:00
/ * *
* { @inheritDoc }
* /
@Override
public String getId ( ) {
return ( String ) this . resourceProperties . get ( ID ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public void setId ( String id ) throws InvalidValueException {
setResourceProperty ( ID , id ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public String getConsumerId ( ) {
return ( String ) this . resourceProperties . get ( CONSUMER_ID ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public void setConsumerId ( String consumerId ) throws InvalidValueException {
setResourceProperty ( CONSUMER_ID , consumerId ) ;
}
protected Calendar timestampStringToCalendar ( long millis ) {
Calendar calendar = Calendar . getInstance ( ) ;
calendar . setTimeInMillis ( millis ) ;
return calendar ;
}
/ * *
* { @inheritDoc }
* /
@Override
public Calendar getCreationTime ( ) {
long millis = ( Long ) this . resourceProperties . get ( CREATION_TIME ) ;
return timestampStringToCalendar ( millis ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public void setCreationTime ( Calendar creationTime ) throws InvalidValueException {
setResourceProperty ( CREATION_TIME , creationTime . getTimeInMillis ( ) ) ;
}
2015-06-26 15:50:39 +02:00
/ * *
* { @inheritDoc }
* /
@Override
public String getScope ( ) {
return ( String ) this . resourceProperties . get ( SCOPE ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public void setScope ( String scope ) throws InvalidValueException {
setResourceProperty ( SCOPE , scope ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
2015-11-30 17:49:18 +01:00
public Map < String , Comparable < ? extends Serializable > > getResourceProperties ( ) {
return new HashMap < String , Comparable < ? extends Serializable > > ( this . resourceProperties ) ;
2015-06-26 15:50:39 +02:00
}
/ * *
* { @inheritDoc }
* /
@Override
2015-11-30 17:49:18 +01:00
public void setResourceProperties ( Map < String , Comparable < ? extends Serializable > > properties ) throws InvalidValueException {
Map < String , Comparable < ? extends Serializable > > validated = validateProperties ( properties ) ;
this . resourceProperties = new HashMap < String , Comparable < ? extends Serializable > > ( validated ) ;
2015-06-26 15:50:39 +02:00
}
/ * *
* { @inheritDoc }
* /
@Override
2015-11-30 17:49:18 +01:00
public Comparable < ? extends Serializable > getResourceProperty ( String key ) {
2015-06-26 15:50:39 +02:00
return this . resourceProperties . get ( key ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
2015-11-30 17:49:18 +01:00
public void setResourceProperty ( String key , Comparable < ? extends Serializable > value ) throws InvalidValueException {
Comparable < ? extends Serializable > checkedValue = validateField ( key , value ) ;
2015-06-26 15:50:39 +02:00
if ( checkedValue = = null ) {
this . resourceProperties . remove ( key ) ;
} else {
this . resourceProperties . put ( key , checkedValue ) ;
}
}
// AGGREGATION
/* --------------------------------------- */
2015-06-24 17:51:46 +02:00
/ * *
* Return the left end of the time interval covered by this { # UsageRecord }
* @return Start Time
* /
protected long getStartTimeInMillis ( ) {
return ( Long ) this . resourceProperties . get ( START_TIME ) ;
}
2015-06-10 17:36:50 +02:00
/ * *
2015-06-15 11:28:19 +02:00
* Return the left end of the time interval covered by this { # UsageRecord }
* @return Start Time
2015-06-10 17:36:50 +02:00
* /
2015-06-15 11:28:19 +02:00
protected Calendar getStartTimeAsCalendar ( ) {
2015-06-24 17:51:46 +02:00
long millis = getStartTimeInMillis ( ) ;
2015-06-10 17:36:50 +02:00
return timestampStringToCalendar ( millis ) ;
}
2015-06-15 11:28:19 +02:00
2015-06-10 17:36:50 +02:00
/ * *
* Set the left end of the time interval covered by this { # UsageRecord }
* @param startTime Start Time
* @throws InvalidValueException
* /
protected void setStartTime ( Calendar startTime ) throws InvalidValueException {
setResourceProperty ( START_TIME , startTime . getTimeInMillis ( ) ) ;
}
2015-06-24 17:51:46 +02:00
/ * *
* Return the right end of the time interval covered by this { # UsageRecord }
* @return End Time
* /
protected long getEndTimeInMillis ( ) {
return ( Long ) this . resourceProperties . get ( END_TIME ) ;
}
2015-06-10 17:36:50 +02:00
/ * *
2015-06-15 11:28:19 +02:00
* Return the right end of the time interval covered by this { # UsageRecord }
* @return End Time
2015-06-10 17:36:50 +02:00
* /
2015-06-15 11:28:19 +02:00
protected Calendar getEndTimeAsCalendar ( ) {
2015-06-24 17:51:46 +02:00
long millis = getEndTimeInMillis ( ) ;
2015-06-10 17:36:50 +02:00
return timestampStringToCalendar ( millis ) ;
}
/ * *
* Set the right end of the time interval covered by this { # UsageRecord }
* @param endTime End Time
* @throws InvalidValueException
* /
protected void setEndTime ( Calendar endTime ) throws InvalidValueException {
setResourceProperty ( END_TIME , endTime . getTimeInMillis ( ) ) ;
}
2015-06-26 15:50:39 +02:00
protected int getOperationCount ( ) {
return ( Integer ) this . resourceProperties . get ( OPERATION_COUNT ) ;
2015-06-10 17:36:50 +02:00
}
2015-06-26 15:50:39 +02:00
protected void setOperationCount ( int operationCount ) throws InvalidValueException {
setResourceProperty ( OPERATION_COUNT , operationCount ) ;
2015-06-10 17:36:50 +02:00
}
2015-06-26 15:50:39 +02:00
/* --------------------------------------- */
2015-06-10 17:36:50 +02:00
2015-11-30 17:49:18 +01:00
protected Comparable < ? extends Serializable > validateField ( String key , Comparable < ? extends Serializable > value ) throws InvalidValueException {
2015-06-10 17:36:50 +02:00
if ( key = = null ) {
throw new InvalidValueException ( " The key of property to set cannot be null " ) ;
}
2015-11-30 17:49:18 +01:00
Comparable < ? extends Serializable > checkedValue = value ;
2015-06-10 17:36:50 +02:00
List < FieldAction > fieldValidators = validation . get ( key ) ;
if ( fieldValidators ! = null ) {
for ( FieldAction fieldValidator : fieldValidators ) {
if ( aggregatedFields . contains ( key ) ) {
// TODO
}
if ( computedFields . contains ( key ) ) {
2015-10-19 17:59:09 +02:00
logger . debug ( " {} is a computed field. To be calculated all the required fields to calcutalate it MUST be set. In any case the provided value will be ignored. " , key ) ;
2015-06-10 17:36:50 +02:00
}
2015-07-13 15:12:21 +02:00
try {
checkedValue = fieldValidator . validate ( key , checkedValue , this ) ;
} catch ( InvalidValueException e ) {
logger . error ( String . format ( " The provided value %s is NOT valid for field with key %s. " , checkedValue . toString ( ) , key ) ) ;
throw e ;
}
2015-06-10 17:36:50 +02:00
}
}
return checkedValue ;
}
2015-11-30 17:49:18 +01:00
protected Map < String , Comparable < ? extends Serializable > > validateProperties ( Map < String , Comparable < ? extends Serializable > > properties ) throws InvalidValueException {
Map < String , Comparable < ? extends Serializable > > validated = new HashMap < String , Comparable < ? extends Serializable > > ( ) ;
2015-06-10 17:36:50 +02:00
for ( String key : properties . keySet ( ) ) {
2015-11-30 17:49:18 +01:00
Comparable < ? extends Serializable > value = properties . get ( key ) ;
validated . put ( key , validateField ( key , value ) ) ;
2015-06-10 17:36:50 +02:00
}
2015-07-08 11:15:54 +02:00
return validated ;
2015-06-10 17:36:50 +02:00
}
/ * *
* { @inheritDoc }
* /
@Override
public void validate ( ) throws InvalidValueException {
validateProperties ( this . resourceProperties ) ;
Set < String > notPresentProperties = new HashSet < String > ( ) ;
for ( String key : this . requiredFields ) {
if ( ! this . resourceProperties . containsKey ( key ) ) {
notPresentProperties . add ( key ) ;
}
}
if ( ! notPresentProperties . isEmpty ( ) ) {
String pluralManagement = notPresentProperties . size ( ) = = 1 ? " y " : " ies " ;
throw new InvalidValueException ( String . format ( " The Usage Record does not contain the following required propert%s %s " , pluralManagement , notPresentProperties . toString ( ) ) ) ;
}
}
@Override
public String toString ( ) {
return resourceProperties . toString ( ) ;
}
/ * *
* { @inheritDoc }
* /
@Override
public OperationResult getOperationResult ( ) {
return OperationResult . valueOf ( ( String ) this . resourceProperties . get ( OPERATION_RESULT ) ) ;
}
/ * *
* { @inheritDoc }
* @throws InvalidValueException
* /
@Override
public void setOperationResult ( OperationResult operationResult ) throws InvalidValueException {
setResourceProperty ( OPERATION_RESULT , operationResult ) ;
}
/ * *
* Compare this UsageRecord instance with the one provided as argument
* @param usageRecord the Usage Record to compare
* @return 0 is and only if the UsageRecord provided as parameter
* contains all and ONLY the parameters contained in this instance .
* If the number of parameters differs , the methods return the difference
* between the number of parameter in this instance and the ones in the
* UsageRecord provided as parameter .
* If the size is the same but the UsageRecord provided as parameter does
* not contains all parameters in this instance , - 1 is returned .
* /
@Override
2015-12-18 17:09:05 +01:00
public int compareTo ( Record record ) {
2015-11-30 17:49:18 +01:00
Set < Entry < String , Comparable < ? extends Serializable > > > thisSet = this . resourceProperties . entrySet ( ) ;
2015-12-18 17:09:05 +01:00
Set < Entry < String , Comparable < ? extends Serializable > > > usageRecordSet = record . getResourceProperties ( ) . entrySet ( ) ;
2015-06-10 17:36:50 +02:00
if ( thisSet . size ( ) ! = usageRecordSet . size ( ) ) {
return thisSet . size ( ) - usageRecordSet . size ( ) ;
}
if ( usageRecordSet . containsAll ( thisSet ) ) {
return 0 ;
}
return 1 ;
}
}