/******************************************************************************* * Copyright 2015 Software Evolution and Architecture Lab, University of Zurich * * 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. ******************************************************************************/ package eu.cloudwave.wp5.feedbackhandler.repositories; import static org.springframework.data.mongodb.core.aggregation.Aggregation.match; import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation; import static org.springframework.data.mongodb.core.aggregation.Aggregation.sort; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationResults; import org.springframework.data.mongodb.core.aggregation.GroupOperation; import org.springframework.data.mongodb.core.aggregation.MatchOperation; import org.springframework.data.mongodb.core.aggregation.SortOperation; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import com.google.common.base.Optional; import eu.cloudwave.wp5.common.model.MetricType; import eu.cloudwave.wp5.common.model.Procedure; import eu.cloudwave.wp5.common.model.ProcedureExecutionMetric; import eu.cloudwave.wp5.common.model.impl.MetricTypeImpl; import eu.cloudwave.wp5.feedbackhandler.aggregations.AggregatedAverage; import eu.cloudwave.wp5.feedbackhandler.aggregations.ProcedureMetricAggregation; import eu.cloudwave.wp5.feedbackhandler.constants.DbTableNames; import eu.cloudwave.wp5.feedbackhandler.model.db.DbApplication; import eu.cloudwave.wp5.feedbackhandler.model.db.impl.DbProcedureExecutionMetricImpl; /** * Implementation of {@link MetricRepositoryCustom}. It is named according to the naming conventions: * <ul> * <li>http://www.javabeat.net/spring-data-custom-repository/</li> * <li>http://stackoverflow.com/a/20789040/3721915</li> * </ul> */ public class MetricRepositoryImpl extends AbstractRepository implements MetricRepositoryCustom { @Autowired private MongoTemplate mongoTemplate; /** * {@inheritDoc} */ @Override public List<? extends ProcedureExecutionMetric> find(final DbApplication application, final Procedure procedure) { return find(application, procedure.getClassName(), procedure.getName(), procedure.getArguments().toArray(new String[procedure.getArguments().size()])); } /** * {@inheritDoc} */ @Override public List<? extends ProcedureExecutionMetric> find(final DbApplication application, final String className, final String procedureName, final String[] procedureArguments) { final Criteria criteria = new Criteria(APPLICATION).is(application).and(PROC__CLASS_NAME).is(className).and(PROC__NAME).is(procedureName).and(PROC__ARGUMENTS).is(procedureArguments); final Sort sort = new Sort(Sort.Direction.ASC, TIMESTAMP); final Query query = new Query(criteria).with(sort); return mongoTemplate.find(query, DbProcedureExecutionMetricImpl.class, DbTableNames.METRICS); } /** * {@inheritDoc} */ @Override public AggregationResults<ProcedureMetricAggregation> aggregateProcedureMetrics(final DbApplication application, final MetricType type) { final MatchOperation matchOperation = match(appCriteria(application).and(TYPE).is(type.toString())); final GroupOperation groupOperation = groupOperation(PROCEDURE); final SortOperation sortOperation = sort(Sort.Direction.DESC, AVERAGE_VALUE); final Aggregation executionTimeAggregationSpec = newAggregation(matchOperation, groupOperation, sortOperation); return aggregate(executionTimeAggregationSpec); } /** * {@inheritDoc} */ @Override public Optional<Double> aggregateExecutionTime(final DbApplication application, final String className, final String name, final String[] arguments) { final String type = MetricTypeImpl.EXECUTION_TIME.toString(); final List<AggregatedAverage> aggregationResults = aggregatedAverage(application, className, name, arguments, type).getMappedResults(); if (!aggregationResults.isEmpty()) { return Optional.of(aggregationResults.get(0).getAverageValue()); } return Optional.absent(); } /** * {@inheritDoc} */ @Override public AggregationResults<AggregatedAverage> aggregateCollectionSizes(final DbApplication application, final String className, final String name, final String[] arguments) { final String type = MetricTypeImpl.COLLECTION_SIZE.toString(); return aggregatedAverage(application, className, name, arguments, type); } private AggregationResults<AggregatedAverage> aggregatedAverage(final DbApplication application, final String className, final String name, final String[] arguments, final String type) { final MatchOperation matchOperation = match(appCriteria(application).and(TYPE).is(type).and(PROC__CLASS_NAME).is(className).and(PROC__NAME).is(name).and(PROC__ARGUMENTS).is(arguments)); // for some reason PROCEDURE is also required in the grouping // (otherwise the aggregation is done correctly but the 'additionalQualifier' in the output-type is null) final GroupOperation groupOperation = groupOperation(PROCEDURE, ADDITIONAL_QUALIFIER); final Aggregation collectionSizeAggregationSpec = newAggregation(matchOperation, groupOperation); return aggregate(collectionSizeAggregationSpec, AggregatedAverage.class); } private AggregationResults<ProcedureMetricAggregation> aggregate(final Aggregation aggregation) { return aggregate(aggregation, ProcedureMetricAggregation.class); } private <O> AggregationResults<O> aggregate(final Aggregation aggregation, final Class<O> outputType) { return mongoTemplate.aggregate(aggregation, DbTableNames.METRICS, outputType); } }