com.thinkbiganalytics.metadata.jpa.sla.JpaServiceLevelAssessor Maven / Gradle / Ivy
/**
*
*/
package com.thinkbiganalytics.metadata.jpa.sla;
/*-
* #%L
* thinkbig-operational-metadata-jpa
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.thinkbiganalytics.metadata.api.MetadataAccess;
import com.thinkbiganalytics.metadata.sla.api.AssessmentResult;
import com.thinkbiganalytics.metadata.sla.api.Metric;
import com.thinkbiganalytics.metadata.sla.api.MetricAssessment;
import com.thinkbiganalytics.metadata.sla.api.Obligation;
import com.thinkbiganalytics.metadata.sla.api.ObligationAssessment;
import com.thinkbiganalytics.metadata.sla.api.ObligationGroup;
import com.thinkbiganalytics.metadata.sla.api.ObligationGroup.Condition;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement.ID;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAssessment;
import com.thinkbiganalytics.metadata.sla.spi.AssessorNotFoundException;
import com.thinkbiganalytics.metadata.sla.spi.MetricAssessmentBuilder;
import com.thinkbiganalytics.metadata.sla.spi.MetricAssessor;
import com.thinkbiganalytics.metadata.sla.spi.ObligationAssessmentBuilder;
import com.thinkbiganalytics.metadata.sla.spi.ObligationAssessor;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAgreementProvider;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
/**
* A service level agreement assessor that will assess service level agreements checking the obligations and metrics and validating if the agreement is violated or not
*/
public class JpaServiceLevelAssessor implements ServiceLevelAssessor {
private static final Logger log = LoggerFactory.getLogger(JpaServiceLevelAssessor.class);
@Inject
MetadataAccess metadataAccess;
@Inject
private JpaServiceLevelAssessmentProvider assessmentProvider;
@Inject
private ServiceLevelAgreementProvider agreementProvider;
private ObligationAssessor extends Obligation> defaultObligationAssessor;
private Set> obligationAssessors;
private Set> metricAssessors;
public JpaServiceLevelAssessor() {
this.obligationAssessors = Collections.synchronizedSet(new HashSet>());
this.metricAssessors = Collections.synchronizedSet(new HashSet>());
this.defaultObligationAssessor = new DefaultObligationAssessor();
}
/*
* (non-Javadoc)
*
* @see com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessor#
* registerObligationAssessor(com.thinkbiganalytics.metadata.sla.spi.
* ObligationAssessor)
*/
@Override
public ObligationAssessor extends Obligation> registerObligationAssessor(ObligationAssessor extends Obligation> assessor) {
this.obligationAssessors.add(assessor);
return assessor;
}
/*
* (non-Javadoc)
*
* @see com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessor#
* registerMetricAssessor(com.thinkbiganalytics.metadata.sla.spi.
* MetricAssessor)
*/
@Override
public MetricAssessor extends Metric, ? extends Serializable> registerMetricAssessor(MetricAssessor extends Metric, ? extends Serializable> assessor) {
this.metricAssessors.add(assessor);
return assessor;
}
private List> sanitizeComparablesArray(Comparable extends Serializable>... comparables) {
List> list = new ArrayList<>();
if (comparables != null) {
for (Comparable extends Serializable> comparable : comparables) {
list.add(sanitizeComparable(comparable));
}
}
return list;
}
private Comparable extends Serializable> sanitizeComparable(Comparable extends Serializable> comparable) {
if (comparable != null && (comparable instanceof Date)) {
return ((Date) comparable).getTime();
} else {
return comparable;
}
}
/**
* Needs to be wrapped in metadataAccess.read
*/
public ServiceLevelAssessment assess(ID id) {
ServiceLevelAgreement sla = agreementProvider.getAgreement(id);
if (sla == null) {
//TODO add explicit NotFoundException
throw new RuntimeException("Failed to get sla node for " + id);
}
return assess(sla);
}
@Override
public ServiceLevelAssessment findLatestAssessment(ServiceLevelAgreement sla) {
return this.metadataAccess.read(() -> assessmentProvider.findLatestAssessment(sla.getId()),
MetadataAccess.SERVICE);
}
/**
* Assess the SLA (coming from JCR)
*
* @param sla the SLA to be assessed
*/
public ServiceLevelAssessment assess(ServiceLevelAgreement sla) {
log.info("Assessing SLA: {}", sla.getName());
ServiceLevelAssessment assessment = null;
ServiceLevelAgreement serviceLevelAgreement = sla;
assessment = this.metadataAccess.commit(() -> {
AssessmentResult combinedResult = AssessmentResult.SUCCESS;
try {
//create the new Assessment
JpaServiceLevelAssessment slaAssessment = new JpaServiceLevelAssessment();
slaAssessment.setId(JpaServiceLevelAssessment.SlaAssessmentId.create());
slaAssessment.setAgreement(serviceLevelAgreement);
List groups = sla.getObligationGroups();
for (ObligationGroup group : groups) {
Condition condition = group.getCondition();
AssessmentResult groupResult = AssessmentResult.SUCCESS;
Set obligationAssessments = new HashSet<>();
log.debug("Assessing obligation group {} with {} obligations", group, group.getObligations().size());
for (Obligation ob : group.getObligations()) {
ObligationAssessment obAssessment = assess(ob, slaAssessment);
obligationAssessments.add(obAssessment);
// slaAssessment.add(obAssessment);
groupResult = groupResult.max(obAssessment.getResult());
}
slaAssessment.setObligationAssessments(obligationAssessments);
// Short-circuit required or sufficient if necessary.
switch (condition) {
case REQUIRED:
if (groupResult == AssessmentResult.FAILURE) {
return completeAssessment(slaAssessment, groupResult);
}
break;
case SUFFICIENT:
if (groupResult != AssessmentResult.FAILURE) {
return completeAssessment(slaAssessment, groupResult);
}
break;
default:
}
// Required condition but non-failure, sufficient condition but non-success, or optional condition:
// continue assessing groups and retain the best of the group results.
combinedResult = combinedResult.max(groupResult);
}
return completeAssessment(slaAssessment, combinedResult);
} finally {
log.debug("Completed assessment of SLA {}: {}", sla.getName(), combinedResult);
}
}, MetadataAccess.SERVICE);
return assessment;
}
private ObligationAssessment assess(Obligation ob, JpaServiceLevelAssessment serviceLevelAssessment) {
ObligationAssessmentBuilderImpl builder = new ObligationAssessmentBuilderImpl(ob, serviceLevelAssessment);
@SuppressWarnings("unchecked")
ObligationAssessor assessor = (ObligationAssessor) findAssessor(ob);
log.debug("Assessing obligation \"{}\" with assessor: {}", assessor);
assessor.assess(ob, builder);
return builder.build();
}
private ServiceLevelAssessment completeAssessment(JpaServiceLevelAssessment slaAssessment, AssessmentResult result) {
slaAssessment.setResult(result);
String slaName = slaAssessment.getAgreement() != null ? slaAssessment.getAgreement().getName() : "";
if (result == AssessmentResult.SUCCESS) {
slaAssessment.setMessage("SLA assessment requirements were met for '" + slaName + "'");
} else {
slaAssessment.setMessage("At least one of the SLA obligations for '" + slaName + "' resulted in the status: " + result);
}
//save it
assessmentProvider.save(slaAssessment);
return slaAssessment;
}
protected ObligationAssessor extends Obligation> findAssessor(Obligation obligation) {
synchronized (this.obligationAssessors) {
for (ObligationAssessor extends Obligation> assessor : this.obligationAssessors) {
if (assessor.accepts(obligation)) {
return assessor;
}
}
}
return this.defaultObligationAssessor;
}
@SuppressWarnings("unchecked")
protected MetricAssessor findAssessor(M metric) {
synchronized (this.metricAssessors) {
for (MetricAssessor extends Metric, ? extends Serializable> accessor : this.metricAssessors) {
if (accessor.accepts(metric)) {
return (MetricAssessor) accessor;
}
}
}
throw new AssessorNotFoundException(metric);
}
private class ObligationAssessmentBuilderImpl implements ObligationAssessmentBuilder {
private Obligation obligation;
private String message = "";
private AssessmentResult result = AssessmentResult.SUCCESS;
private Comparator comparator;
private List> comparables;
private ServiceLevelAssessment serviceLevelAssessment;
private JpaObligationAssessment assessment;
public ObligationAssessmentBuilderImpl(Obligation obligation, JpaServiceLevelAssessment serviceLevelAssessment) {
this.obligation = obligation;
this.assessment = new JpaObligationAssessment();
this.assessment.setObligation(obligation);
this.serviceLevelAssessment = serviceLevelAssessment;
serviceLevelAssessment.getObligationAssessments().add(this.assessment);
this.assessment.setServiceLevelAssessment(serviceLevelAssessment);
}
@Override
public ObligationAssessmentBuilder obligation(Obligation ob) {
this.obligation = ob;
return this;
}
@Override
public ObligationAssessmentBuilder result(AssessmentResult result) {
this.result = result;
return this;
}
@Override
public ObligationAssessmentBuilder message(String descr) {
this.message = descr;
return this;
}
@Override
public ObligationAssessmentBuilder comparator(Comparator comp) {
this.comparator = comp;
return this;
}
@Override
@SuppressWarnings("unchecked")
public ObligationAssessmentBuilder compareWith(final Comparable extends Serializable> value,
@SuppressWarnings("unchecked")
final Comparable extends Serializable>... otherValues) {
this.comparables = new ArrayList>(Arrays.asList(sanitizeComparable(value)));
this.comparables.addAll(sanitizeComparablesArray(otherValues));
return this;
}
@Override
public MetricAssessment> assess(M metric) {
MetricAssessor assessor = findAssessor(metric);
MetricAssessmentBuilderImpl builder = new MetricAssessmentBuilderImpl(metric, this.assessment);
assessor.assess(metric, builder);
MetricAssessment> metricAssmt = builder.build();
return metricAssmt;
}
protected ObligationAssessment build() {
this.assessment.setObligation(this.obligation);
this.assessment.setMessage(this.message);
this.assessment.setResult(this.result);
if (this.comparator != null) {
this.assessment.setComparator(this.comparator);
}
if (this.comparables != null) {
this.assessment.setComparables(this.comparables);
}
this.serviceLevelAssessment.getObligationAssessments().add(this.assessment);
return this.assessment;
}
}
private class MetricAssessmentBuilderImpl implements MetricAssessmentBuilder {
private Metric metric;
private String message = "";
private AssessmentResult result = AssessmentResult.SUCCESS;
private D data;
private Comparator> comparator;
private List> comparables;
private JpaObligationAssessment obligationAssessment;
public MetricAssessmentBuilderImpl(Metric metric, JpaObligationAssessment obligationAssessment) {
this.obligationAssessment = obligationAssessment;
this.metric = metric;
}
/**
* not used
**/
public MetricAssessmentBuilderImpl(Metric metric) {
this.metric = metric;
}
/**
* not used
**/
@Override
public MetricAssessmentBuilder metric(Metric metric) {
this.metric = metric;
return this;
}
@Override
public MetricAssessmentBuilder message(String descr) {
this.message = descr;
return this;
}
@Override
public MetricAssessmentBuilder result(AssessmentResult result) {
this.result = result;
return this;
}
@Override
public MetricAssessmentBuilder data(D data) {
this.data = data;
return this;
}
@Override
public MetricAssessmentBuilder comparitor(Comparator> comp) {
this.comparator = comp;
return this;
}
@Override
@SuppressWarnings("unchecked")
public MetricAssessmentBuilder compareWith(Comparable extends Serializable> value,
Comparable extends Serializable>... otherValues) {
this.comparables = new ArrayList>(Arrays.asList(sanitizeComparable(value)));
this.comparables.addAll(sanitizeComparablesArray(otherValues));
return this;
}
protected MetricAssessment build() {
JpaMetricAssessment assessment = new JpaMetricAssessment<>();
assessment.setMetric(this.metric);
assessment.setMessage(this.message);
assessment.setResult(this.result);
assessment.setMetricDescription(this.metric.getDescription());
//assessment.setData(this.data);
if (this.comparator != null) {
assessment.setComparator(this.comparator);
}
if (this.comparables != null) {
assessment.setComparables(this.comparables);
}
obligationAssessment.getMetricAssessments().add(assessment);
assessment.setObligationAssessment(obligationAssessment);
return assessment;
}
}
protected class DefaultObligationAssessor implements ObligationAssessor {
@Override
public boolean accepts(Obligation obligation) {
// Accepts any obligations
return true;
}
@Override
public void assess(Obligation obligation, ObligationAssessmentBuilder builder) {
log.debug("Assessing obligation '{}' with {} metrics", obligation, obligation.getMetrics().size());
Set metricAssessments = new HashSet();
ObligationAssessmentBuilderImpl obligationAssessmentBuilder = (ObligationAssessmentBuilderImpl) builder;
AssessmentResult result = AssessmentResult.SUCCESS;
for (Metric metric : obligation.getMetrics()) {
log.debug("Assessing obligation metric '{}'", metric);
MetricAssessment assessment = obligationAssessmentBuilder.assess(metric);
metricAssessments.add(assessment);
}
for (MetricAssessment ma : metricAssessments) {
result = result.max(ma.getResult());
}
String message = "The obligation requirements were met";
if (result != AssessmentResult.SUCCESS) {
message = "At least one metric assessment resulted in the status: " + result;
}
log.debug("Assessment outcome '{}'", message);
builder
.result(result)
.message(message)
.obligation(obligation);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy