/*
Copyright 2012 Christian Prause and Fraunhofer FIT
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 net.sf.collabreview.reputation;
import net.sf.collabreview.core.Artifact;
import net.sf.collabreview.core.ArtifactIdentifier;
import net.sf.collabreview.core.Repository;
import net.sf.collabreview.core.configuration.ConfigurationData;
import net.sf.collabreview.core.users.Author;
import net.sf.collabreview.hooks.SetReviewHook;
import net.sf.collabreview.repository.Review;
import java.util.*;
/**
* The number of reviews for artifacts that no one else has reviewed.
*
* @author Christian Prause (chris)
* @date 2010-09-26 17:22:50
*/
public class MetricLoneRanger extends ReputationMetric implements SetReviewHook {
/*
* Apache commons logging logger for class MetricLoneRanger.
*/
//private static final Log logger = LogFactory.getLog(MetricLoneRanger.class);
/**
* The number of lone ranger reviews per author.
*/
private Map<Author, Float> reviews;
@Override
public int getPriority() {
return PRIORITY_MEDIUM;
}
@Override
protected void configure(ConfigurationData configuration) throws Exception {
getRepository().registerSetReviewHook(this);
}
@Override
protected void destroy() {
}
@Override
protected void beginVisiting() {
reviews = new HashMap<Author, Float>();
}
@Override
protected void visit(Artifact artifact) {
if (getFilter() != null && !getFilter().filter(artifact)) {
return;
}
Collection<Review> reviews = artifact.getReviewsFromRepository();
if (reviews.size() == 1) {
Review review = reviews.iterator().next();
increment(review.getAuthor());
}
}
@Override
protected Map<String, Float> endVisiting() {
return translateNewData();
}
protected Map<String, Float> translateNewData() {
Map<String, Float> result = new HashMap<String, Float>();
for (Author author : reviews.keySet()) {
result.put(author.getName(), reviews.get(author));
}
return result;
}
@Override
protected String getDefaultName() {
return "loneranger";
}
private void increment(Author author) {
Float oldValue = this.reviews.get(author);
this.reviews.put(author, oldValue == null ? 1 : oldValue + 1);
}
private void decrement(Author author) {
Float oldValue = this.reviews.get(author);
assert oldValue != null; // there must already be a value
this.reviews.put(author, oldValue - 1);
}
public synchronized void reviewUpdated(Repository repository, Review oldReview, Review newReview) {
if (reviews == null || isUpdateInProgress()) {
setUpToDate(false);
return;
}
ArtifactIdentifier artifactIdentifier = newReview.getArtifactIdentifier();
if (getFilter() != null && !getFilter().filter(artifactIdentifier, repository)) {
return;
}
Collection<Review> reviews = repository.listReviews(artifactIdentifier.getName(), artifactIdentifier.getBranch());
Set<Author> authors = new HashSet<Author>();
Author secondReviewer = null;
for (Review review : reviews) {
authors.add(review.getAuthor());
if (!review.getAuthor().equals(newReview.getAuthor())) {
secondReviewer = review.getAuthor();
}
}
authors.add(newReview.getAuthor()); // depending on Repository implementation the review may or may not be in the reviews collection at this time
// update lone ranger counts?
assert authors.size() > 0;
if (oldReview != null) { // if the oldReview != null => only an update => no change
return;
}
if (authors.size() == 1) { // review is the only one => increment counter
increment(newReview.getAuthor());
} else if (authors.size() == 2) { // review is no longer the only one => decrement counter
decrement(secondReviewer);
} // if more than two authors then the new review cannot have an effect
// update score value
setAuthorScores(translateNewData());
}
}