net.anotheria.extensions.php.mappers.AbstractOnDemandStatsProducerMapper Maven / Gradle / Ivy
The newest version!
package net.anotheria.extensions.php.mappers;
import net.anotheria.extensions.php.dto.PHPProducerDTO;
import net.anotheria.extensions.php.dto.PHPStatsDTO;
import net.anotheria.extensions.php.exceptions.MappingException;
import net.anotheria.moskito.core.dynamic.IOnDemandStatsFactory;
import net.anotheria.moskito.core.dynamic.OnDemandStatsProducer;
import net.anotheria.moskito.core.dynamic.OnDemandStatsProducerException;
import net.anotheria.moskito.core.producers.IStats;
import net.anotheria.moskito.core.producers.IStatsProducer;
import net.anotheria.moskito.core.registry.IProducerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract mapper to handle {@link OnDemandStatsProducer} class
* producers.
*
* Has defined {@link Mapper#mapProducer(IProducerRegistry, PHPProducerDTO)}
* method. But it is required to define {@link AbstractOnDemandStatsProducerMapper#getStatsFactory()}
* and {@link AbstractOnDemandStatsProducerMapper#updateStats(IStats, StatsValues)}
* methods in child mappers instead.
*
* Due to OnDemandStatsProducer instances can have different stats classes
* this class checks that generic type of producer from repository stats
* be same as generic type of child mapper.
*
* @param stats class that mapper used
*/
public abstract class AbstractOnDemandStatsProducerMapper implements Mapper {
private static final Logger log = LoggerFactory.getLogger(AbstractOnDemandStatsProducerMapper.class);
/**
* Updates stats instance using given incoming data
*
* @param stats stats instance to update
* @param values new data to update stats
* @throws MappingException on invalid incoming stats data
*/
public abstract void updateStats(S stats, StatsValues values) throws MappingException;
/**
* Returns factory for mapper stats
* @return factory for mapper stats
*/
public abstract IOnDemandStatsFactory getStatsFactory();
/**
* Class of stats used by mapper.
* Required to check is incoming producer can
* be updated using this mapper
*/
private Class statsClass;
/**
* Constructor with stats class argument
* @param statsClass class of stats that can be updated by this mapper
*/
public AbstractOnDemandStatsProducerMapper(Class statsClass) {
this.statsClass = statsClass;
}
/**
* Casts producer of raw type from producers repository
* to {@link OnDemandStatsProducer} with producer stats class
* check.
*
* @param producer producer to be casted
* @return casted producer
* @throws ClassCastException if producer is not instance of {@link OnDemandStatsProducer}
* or generic type of producer stats is not same as type of mapper
*/
@SuppressWarnings("unchecked")
// Justification : producer generic type is checked manually at runtime
private OnDemandStatsProducer safeCastProducer(IStatsProducer producer) throws ClassCastException {
OnDemandStatsProducer onDemandStatsTypedProducer =
(OnDemandStatsProducer)producer;
// Checking is generic type of producer is corresponds to generic type of mapper
// By retrieving producer default stats and checking it type
if(!(statsClass.isInstance(onDemandStatsTypedProducer.getDefaultStats())))
throw new ClassCastException(
"Producer do not have generic type of " +
statsClass.getCanonicalName() + " required by mapper"
);
return onDemandStatsTypedProducer;
}
@Override
public void mapProducer(IProducerRegistry producerRegistry, PHPProducerDTO producerDTO) throws MappingException {
log.debug("Starting to map producer with id '{}'...", producerDTO.getProducerId());
OnDemandStatsProducer producer;
IStatsProducer producerUncasted = producerRegistry.getProducer(producerDTO.getProducerId());
if (producerUncasted != null){
try {
producer = safeCastProducer(producerUncasted);
} catch (ClassCastException e) {
throw new MappingException("Cannot update producer data. Producer with id '" +
producerDTO.getProducerId() +
"' actual type is differs from mapper requirements type.", e);
}
}
else{
log.debug("Producer with id '{}' is not found in repository. " +
"Creating new producer with category '{}', subsystem '{}' and stats class '{}'...",
producerDTO.getProducerId(), producerDTO.getCategory(),
producerDTO.getSubsystem(), statsClass.getName()
);
producer = new OnDemandStatsProducer<>(
producerDTO.getProducerId(),
producerDTO.getCategory(),
producerDTO.getSubsystem(),
getStatsFactory()
);
producerRegistry.registerProducer(producer);
}
for (PHPStatsDTO statsDTO : producerDTO.getStats()) {
try {
StatsValues statsValues = new StatsValues(statsDTO.getValues());
this.updateStats(
producer.getStats(statsDTO.getName()),
statsValues
);
this.updateStats(producer.getDefaultStats(), statsValues);
} catch (OnDemandStatsProducerException e) {
log.error("Failed to get stats with name '" + statsDTO.getName() + "' from producer", e);
} catch (MappingException | IllegalArgumentException e) {
log.error("Failed to map stats with name '" + statsDTO.getName() + "'", e);
}
}
}
}