Index: lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/EmailAnalysisBuilder.java =================================================================== diff -u -rd2a6e36df5b56c2f3f1ddd18dfca6364cfa309df -re4074ec4e7813548c96d2338da3b42d3239b91de --- lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/EmailAnalysisBuilder.java (.../EmailAnalysisBuilder.java) (revision d2a6e36df5b56c2f3f1ddd18dfca6364cfa309df) +++ lams_tool_preview/src/java/org/lamsfoundation/lams/tool/peerreview/util/EmailAnalysisBuilder.java (.../EmailAnalysisBuilder.java) (revision e4074ec4e7813548c96d2338da3b42d3239b91de) @@ -46,18 +46,18 @@ private IPeerreviewService service; private MessageService messageService; - // same across the whole lesson + // same across the whole lesson private String htmlCriteriaTableStart; private String htmlCriteriaTableEnd; private String htmlOverallResultsTable; // htmlORTHighlightedCellReplacementText used to highlight the correct cell in the final table. This allows the table to be generated once for the session and then // updated for each user - private String htmlORTHighlightedCellReplacementText = "%%%%REPLACESTYLEWITHHIGHLIGHT%%%%"; - + private String htmlORTHighlightedCellReplacementText = "%%%%REPLACESTYLEWITHHIGHLIGHT%%%%"; + // Criterias to report on in the top table. Does not include comments. Always use this for the criteria table so that the order is the same and the data matches the heading! - private List criteriaForCriteriaTable = new ArrayList(); - private Map learnerDataMap = new TreeMap(); // lams user id, learner data - private Map groupAveragePerCriteria = new HashMap(); // key activity id, session wide average of the learner's averages (peerRatingIncSelf) + private List criteriaForCriteriaTable = new ArrayList<>(); + private Map learnerDataMap = new TreeMap<>(); // lams user id, learner data + private Map groupAveragePerCriteria = new HashMap<>(); // key activity id, session wide average of the learner's averages (peerRatingIncSelf) private Double averageOfAverages; // Average of individualCriteriaAverage across all activities private int countNonCommentCriteria = 0; @@ -87,15 +87,15 @@ this.messageService = messageService; criterias = ratingService.getCriteriasByToolContentId(peerreview.getContentId()); - preGenerateBoilerplate(); + preGenerateBoilerplate(); selfRatingString = getLocalisedMessage("email.self.rating"); peerRatingString = getLocalisedMessage("email.peers.rating"); } public Map generateHTMLEmailsForSession() { - HashMap emailMap = new HashMap(); + HashMap emailMap = new HashMap<>(); generateTeamData(); for (Map.Entry entry : learnerDataMap.entrySet()) { emailMap.put(entry.getKey(), buildEmail(entry.getKey())); @@ -147,26 +147,28 @@ } public String name; - public Map criteriaDataMap = new HashMap(); // Criteria id as key + public Map criteriaDataMap = new HashMap<>(); // Criteria id as key public Double individualCriteriaAverage; // average of peerRatingIncSelf across all activities - public List commentDTOs = new ArrayList(); + public List commentDTOs = new ArrayList<>(); private Double spa = null; private Double sapa = null; LearnerData(String name) { this.name = name; } - protected void addCriteraDataRow(Long criteraId, Double selfRating, - Double peerRatingExcSelf, Double peerRatingIncSelf) { - criteriaDataMap.put(criteraId, - new SingleCriteriaData(selfRating, peerRatingExcSelf, peerRatingIncSelf)); + protected void addCriteraDataRow(Long criteraId, Double selfRating, Double peerRatingExcSelf, + Double peerRatingIncSelf) { + criteriaDataMap.put(criteraId, new SingleCriteriaData(selfRating, peerRatingExcSelf, peerRatingIncSelf)); } // must not be called until data analysis calculations are done - needs averageOfAverages protected Double getSPAFactor() { if (spa == null) { - spa = (averageOfAverages > 0 && individualCriteriaAverage != null) ? individualCriteriaAverage / averageOfAverages : 0D; + spa = (averageOfAverages > 0 && individualCriteriaAverage != null) + // round twice for consistency with Spreadsheet export + ? roundTo2Places(roundTo2Places(individualCriteriaAverage) / roundTo2Places(averageOfAverages)) + : 0D; } return spa; } @@ -179,7 +181,7 @@ sumSelfRatings += criteriaData.selfRating; sumPeerRatings += criteriaData.peerRatingExcSelf; } - sapa = sumPeerRatings > 0 ? Math.sqrt(sumSelfRatings / sumPeerRatings) : 0d; + sapa = sumPeerRatings > 0 ? roundTo2Places(Math.sqrt(sumSelfRatings / sumPeerRatings)) : 0d; } return sapa; } @@ -195,14 +197,18 @@ } } - private String roundTo2Places(Double d) { - if (d == null || Double.isNaN(d)) - return "0"; + private String roundTo2PlacesAsString(Double d) { + return NumberUtil.formatLocalisedNumberForceDecimalPlaces(roundTo2Places(d), (Locale) null, 2); + } + private double roundTo2Places(double d) { + if (Double.isNaN(d)) { + return 0D; + } + BigDecimal bd = new BigDecimal(d); bd = bd.setScale(2, RoundingMode.HALF_UP); - - return NumberUtil.formatLocalisedNumberForceDecimalPlaces(bd.doubleValue(), (Locale) null, 2); + return bd.doubleValue(); } /* Only needs to be called once for the session - works out all the basic data for the whole team */ @@ -214,22 +220,22 @@ new LearnerData(StringEscapeUtils.escapeCsv(user.getFirstName() + " " + user.getLastName()))); } - Map criteriaMarkSumMap = new HashMap(); - Map criteriaMarkCountMap = new HashMap(); + Map criteriaMarkSumMap = new HashMap<>(); + Map criteriaMarkCountMap = new HashMap<>(); double averageOfAveragesSum = 0d; int averageOfAveragesCount = 0; // Process all the criterias and build up the summary data for each rated user. Store in temporary map. HashMap> tally = processRawRatingData(); // Now calculate the averages / self values and store ready for output - for ( Map.Entry> itemEntry : tally.entrySet()) { + for (Map.Entry> itemEntry : tally.entrySet()) { Long itemId = itemEntry.getKey(); HashMap itemMap = itemEntry.getValue(); Double userMarkSum = 0D; LearnerData learnerData = learnerDataMap.get(itemId); - for ( Map.Entry criteriaEntry : itemMap.entrySet() ) { + for (Map.Entry criteriaEntry : itemMap.entrySet()) { Long criteriaId = criteriaEntry.getKey(); SummingData sd = criteriaEntry.getValue(); @@ -273,27 +279,28 @@ } class SummingData { - float selfRating = 0f; - float peerRatingExcSelf = 0f; - int numRatingsExcSelf = 0; - float peerRatingIncSelf = 0f; - int numRatingsIncSelf = 0; - } + float selfRating = 0f; + float peerRatingExcSelf = 0f; + int numRatingsExcSelf = 0; + float peerRatingIncSelf = 0f; + int numRatingsIncSelf = 0; + } - /** + /** * tally: hashmap> * tallying done in Java as the code to do three calcs in one SQL is complex (and hence risks errors) - * and hopefully we are only dealing with small numbers of users in each session. The code that gets the existing data + * and hopefully we are only dealing with small numbers of users in each session. The code that gets the existing + * data * does a lot of processing that is not needed for the SPA/SAPA calculations so getting the raw data * avoids that processing. */ @SuppressWarnings("unchecked") private HashMap> processRawRatingData() { - Collection criteriaIds = new ArrayList(); + Collection criteriaIds = new ArrayList<>(); for (RatingCriteria criteria : criteriaForCriteriaTable) { criteriaIds.add(criteria.getRatingCriteriaId()); } - HashMap> tally = new HashMap>(); + HashMap> tally = new HashMap<>(); if (criteriaIds.size() > 0) { List rawRatingsForSession = ratingService.getRatingsByCriteriasAndItems(criteriaIds, learnerDataMap.keySet()); @@ -303,7 +310,7 @@ Long itemId = rating.getItemId(); HashMap itemMap = tally.get(itemId); if (itemMap == null) { - itemMap = new HashMap(); + itemMap = new HashMap<>(); sd = new SummingData(); itemMap.put(rating.getRatingCriteria().getRatingCriteriaId(), sd); tally.put(itemId, itemMap); @@ -348,7 +355,7 @@ htmlText.append(htmlCriteriaTableStart).append("") .append(learnerData.name).append(""); for (RatingCriteria criteria : criteriaForCriteriaTable) { - String criteriaComparison = roundTo2Places( + String criteriaComparison = roundTo2PlacesAsString( learnerData.getCriteriaComparison(criteria.getRatingCriteriaId())); htmlText.append("") .append(criteriaComparison).append(""); @@ -361,14 +368,14 @@ private void generateSelfPeerTable(StringBuilder htmlText, LearnerData learnerData) { boolean spaDone = false; boolean evenRow = false; - String spaFactor = roundTo2Places(learnerData.getSPAFactor()); - String sapaFactor = roundTo2Places(learnerData.getSAPAFactor()); + String spaFactor = roundTo2PlacesAsString(learnerData.getSPAFactor()); + String sapaFactor = roundTo2PlacesAsString(learnerData.getSAPAFactor()); htmlText.append(""); for (RatingCriteria criteria : criteriaForCriteriaTable) { SingleCriteriaData criteriaData = learnerData.criteriaDataMap.get(criteria.getRatingCriteriaId()); if (criteriaData != null) { - String selfRating = roundTo2Places(criteriaData.selfRating); - String peerRatingExcSelf = roundTo2Places(criteriaData.peerRatingExcSelf); + String selfRating = roundTo2PlacesAsString(criteriaData.selfRating); + String peerRatingExcSelf = roundTo2PlacesAsString(criteriaData.peerRatingExcSelf); htmlText.append(""); + .append(roundTo2PlacesAsString(criteriaData.peerRatingIncSelf)).append(""); htmlText.append("\n"); evenRow = !evenRow; } else { @@ -459,45 +466,50 @@ private void generateSAPASPAExplanation(StringBuilder htmlText, double rawSPA, double rawSAPA) { - // The SPA/SAPA comparisons are based on values rounded to 1 decimal place. So a value of 0.98 or 1.02 is considered 1, - // while 1.06 is considered > 1. - double spa = new BigDecimal(rawSPA).setScale(1, RoundingMode.HALF_UP).doubleValue(); - double sapa = new BigDecimal(rawSAPA).setScale(1, RoundingMode.HALF_UP).doubleValue(); - + // The SPA/SAPA comparisons are based on values rounded to 2 decimal places + double spa = new BigDecimal(rawSPA).setScale(2, RoundingMode.HALF_UP).doubleValue(); + double sapa = new BigDecimal(rawSAPA).setScale(2, RoundingMode.HALF_UP).doubleValue(); + int cellToHighlight; if (sapa < 1.0) { - if (spa < 1.0) + if (spa < 1.0) { cellToHighlight = 1; - else if (spa > 1.0) + } else if (spa > 1.0) { cellToHighlight = 3; - else + } else { cellToHighlight = 2; + } } else if (sapa > 1.0) { - if (spa < 1.0) + if (spa < 1.0) { cellToHighlight = 7; - else if (spa > 1.0) + } else if (spa > 1.0) { cellToHighlight = 9; - else + } else { cellToHighlight = 8; + } } else { - if (spa < 1.0) + if (spa < 1.0) { cellToHighlight = 4; - else if (spa > 1.0) + } else if (spa > 1.0) { cellToHighlight = 6; - else + } else { cellToHighlight = 5; + } } - - String customisedtableTextToModify = htmlOverallResultsTable.replace(htmlORTHighlightedCellReplacementText+cellToHighlight, highlightBackgroundStyle); - for ( int i=1; i<10; i++ ) { - if ( i != cellToHighlight ) - customisedtableTextToModify = customisedtableTextToModify.replaceAll(htmlORTHighlightedCellReplacementText+i, ""); + + String customisedtableTextToModify = htmlOverallResultsTable + .replace(htmlORTHighlightedCellReplacementText + cellToHighlight, highlightBackgroundStyle); + for (int i = 1; i < 10; i++) { + if (i != cellToHighlight) { + customisedtableTextToModify = customisedtableTextToModify + .replaceAll(htmlORTHighlightedCellReplacementText + i, ""); + } } htmlText.append(customisedtableTextToModify); } - - // only needs to be run once for a session + + // only needs to be run once for a session private void preGenerateBoilerplate() { int numCol = 1; @@ -529,16 +541,17 @@ // SPA / SAPA comparison results table tempBuffer = new StringBuilder(); - + tempBuffer.append("
").append(criteria.getTitle()) .append("\n
").append("Self & Peers' Rating") .append("") - .append(roundTo2Places(criteriaData.peerRatingIncSelf)).append("
\n"); - tempBuffer.append(""); + tempBuffer.append(""); tempBuffer.append("\n
 ") - .append(getLocalisedMessage("email.explanation.SPA.less.one")).append("") - .append(getLocalisedMessage("email.explanation.SPA.one")).append("") - .append(getLocalisedMessage("email.explanation.SPA.greater.one")).append("
 ").append(getLocalisedMessage("email.explanation.SPA.less.one")) + .append("").append(getLocalisedMessage("email.explanation.SPA.one")) + .append("").append(getLocalisedMessage("email.explanation.SPA.greater.one")) + .append("
")