diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2013-10-20 23:14:51 -0700 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2013-10-20 23:14:51 -0700 |
commit | e472550fe154f0afa5b36d2a7e2334d4680d7884 (patch) | |
tree | 8131e3fa7db162f9a072ef4d89e7fb25d338cdd4 /src/com/p4square/grow/backend/resources | |
parent | 31303114ef03b13ab320ee553f11a73346be7f4a (diff) |
First stage of a major refactoring.
Question and Answer can now be serialized and deserialized to/from JSON.
As such, I no longer have to pass awkward maps around. As part of this
change I have introduced a Provider interface to abstract out loading
and persisting these beans.
The scoring logic has been completed factored out of
SurveyResultsResource and into the various ScoringEngines. Tests have
been added for Question, Answer, and the ScoringEngines. A bug has been
fixed in computing the value for slider questions.
The label identifiers in the circle questions have changed from all
lower case to camel case. That is, topleft is now topLeft. Several
issues have been corrected in the circle answers where the point values
did not match the labels.
Testing and code coverage support and reports have been added.
Diffstat (limited to 'src/com/p4square/grow/backend/resources')
4 files changed, 33 insertions, 209 deletions
diff --git a/src/com/p4square/grow/backend/resources/Point.java b/src/com/p4square/grow/backend/resources/Point.java deleted file mode 100644 index e1b15a8..0000000 --- a/src/com/p4square/grow/backend/resources/Point.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -/** - * Simple double based point class. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -class Point { - public static Point valueOf(String str) { - final int comma = str.indexOf(','); - if (comma == -1) { - throw new IllegalArgumentException("Malformed point string"); - } - - final String sX = str.substring(0, comma); - final String sY = str.substring(comma + 1); - - return new Point(Double.valueOf(sX), Double.valueOf(sY)); - } - - private final double mX; - private final double mY; - - public Point(double x, double y) { - mX = x; - mY = y; - } - - public double distance(Point other) { - final double dx = mX - other.mX; - final double dy = mY - other.mY; - - return Math.sqrt(dx*dx + dy*dy); - } - - public double getX() { - return mX; - } - - public double getY() { - return mY; - } - - @Override - public String toString() { - return String.format("%.2f,%.2f", mX, mY); - } -} diff --git a/src/com/p4square/grow/backend/resources/Score.java b/src/com/p4square/grow/backend/resources/Score.java deleted file mode 100644 index 6f52c02..0000000 --- a/src/com/p4square/grow/backend/resources/Score.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -/** - * Simple structure containing a score's sum and count. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -class Score { - /** - * Return the integer value for the given Score String. - */ - public static int numericScore(String score) { - if ("teacher".equals(score)) { - return 4; - } else if ("disciple".equals(score)) { - return 3; - } else if ("believer".equals(score)) { - return 2; - } else { - return 1; - } - } - - double sum; - int count; - - @Override - public String toString() { - final double score = sum / count; - - if (score >= 4) { - return "teacher"; - - } else if (score >= 3) { - return "disciple"; - - } else if (score >= 2) { - return "believer"; - - } else { - return "seeker"; - } - } - -} diff --git a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java index f0bb2aa..91d4d0f 100644 --- a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java +++ b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java @@ -14,16 +14,20 @@ import org.codehaus.jackson.map.ObjectMapper; import org.restlet.data.MediaType; import org.restlet.data.Status; -import org.restlet.resource.ServerResource; import org.restlet.representation.Representation; import org.restlet.representation.StringRepresentation; +import org.restlet.resource.ServerResource; import org.apache.log4j.Logger; -import com.p4square.grow.model.Answer; -import com.p4square.grow.model.Question; import com.p4square.grow.backend.GrowBackend; import com.p4square.grow.backend.db.CassandraDatabase; +import com.p4square.grow.model.Answer; +import com.p4square.grow.model.Question; +import com.p4square.grow.model.RecordedAnswer; +import com.p4square.grow.model.Score; +import com.p4square.grow.provider.Provider; + /** * Store the user's answers to the assessment and generate their score. @@ -31,15 +35,16 @@ import com.p4square.grow.backend.db.CassandraDatabase; * @author Jesse Morgan <jesse@jesterpm.net> */ public class SurveyResultsResource extends ServerResource { - private final static Logger cLog = Logger.getLogger(SurveyResultsResource.class); + private static final Logger LOG = Logger.getLogger(SurveyResultsResource.class); - private final static ObjectMapper MAPPER = new ObjectMapper(); + private static final ObjectMapper MAPPER = new ObjectMapper(); static enum RequestType { ASSESSMENT, ANSWER } private CassandraDatabase mDb; + private Provider<String, Question> mQuestionProvider; private RequestType mRequestType; private String mUserId; @@ -51,6 +56,7 @@ public class SurveyResultsResource extends ServerResource { final GrowBackend backend = (GrowBackend) getApplication(); mDb = backend.getDatabase(); + mQuestionProvider = backend.getQuestionProvider(); mUserId = getAttribute("userId"); mQuestionId = getAttribute("questionId"); @@ -105,7 +111,7 @@ public class SurveyResultsResource extends ServerResource { success = true; } catch (Exception e) { - cLog.warn("Caught exception putting answer: " + e.getMessage(), e); + LOG.warn("Caught exception putting answer: " + e.getMessage(), e); } break; @@ -146,18 +152,30 @@ public class SurveyResultsResource extends ServerResource { continue; } - final String questionId = c.getName(); - final String answerId = c.getStringValue(); - if (!scoringDone) { - scoringDone = !scoreQuestion(score, questionId, answerId); + try { + Question question = mQuestionProvider.get(c.getName()); + RecordedAnswer userAnswer = MAPPER.readValue(c.getStringValue(), RecordedAnswer.class); + + if (question == null) { + LOG.warn("Answer for unknown question: " + c.getName()); + continue; + } + + LOG.error("Scoring questionId: " + c.getName()); + scoringDone = !question.scoreAnswer(score, userAnswer); + + } catch (Exception e) { + LOG.error("Failed to score question: {userid: \"" + mUserId + + "\", questionid:\"" + c.getName() + + "\", userAnswer:\"" + c.getStringValue() + "\"}", e); } totalAnswers++; } - sb.append(", \"score\":" + score.sum / score.count); - sb.append(", \"sum\":" + score.sum); - sb.append(", \"count\":" + score.count); + sb.append(", \"score\":" + score.getScore()); + sb.append(", \"sum\":" + score.getSum()); + sb.append(", \"count\":" + score.getCount()); sb.append(", \"totalAnswers\":" + totalAnswers); sb.append(", \"result\":\"" + score.toString() + "\""); } @@ -170,99 +188,4 @@ public class SurveyResultsResource extends ServerResource { return summary; } - - private boolean scoreQuestion(final Score score, final String questionId, - final String answerJson) { - - final String data = mDb.getKey("strings", "/questions/" + questionId); - - try { - final Map<?,?> questionMap = MAPPER.readValue(data, Map.class); - final Map<?,?> answerMap = MAPPER.readValue(answerJson, Map.class); - final Question question = new Question((Map<String, Object>) questionMap); - final String answerId = (String) answerMap.get("answerId"); - - switch (question.getType()) { - case TEXT: - case IMAGE: - final Answer answer = question.getAnswers().get(answerId); - if (answer == null) { - cLog.warn("Got unknown answer " + answerId - + " for question " + questionId); - } else { - if (!scoreAnswer(score, answer)) { - return false; // Quit scoring - } - } - break; - - case SLIDER: - score.sum += Double.valueOf(answerId) * 4 + 1; - score.count++; - break; - - case CIRCLE: - case QUAD: - scoreQuad(score, question, answerId); - break; - } - - } catch (Exception e) { - cLog.error("Exception parsing question id " + questionId, e); - } - - return true; - } - - private boolean scoreAnswer(final Score score, final Answer answer) { - switch (answer.getType()) { - case TRUMP: - score.sum = answer.getScoreFactor(); - score.count = 1; - return false; // Quit scoring. - - case AVERAGE: - score.sum += answer.getScoreFactor(); - score.count++; - break; - - case NONE: - break; - } - - return true; // Continue scoring - } - - private boolean scoreQuad(final Score score, final Question question, - final String answerId) { - - Point[] answers = new Point[question.getAnswers().size()]; - { - int i = 0; - for (String answer : question.getAnswers().keySet()) { - answers[i++] = Point.valueOf(answer); - } - } - - Point userAnswer = Point.valueOf(answerId); - - double minDistance = Double.MAX_VALUE; - int answerIndex = 0; - for (int i = 0; i < answers.length; i++) { - final double distance = userAnswer.distance(answers[i]); - if (distance < minDistance) { - minDistance = distance; - answerIndex = i; - } - } - - cLog.debug("Quad " + question.getId() + ": Got answer " - + answers[answerIndex].toString() + " for user point " + answerId); - - final Answer answer = question.getAnswers().get(answers[answerIndex].toString()); - score.sum += answer.getScoreFactor(); - score.count++; - - return true; // Continue scoring - } } diff --git a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java index 009d0fe..6de9507 100644 --- a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java +++ b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java @@ -27,6 +27,8 @@ import org.apache.log4j.Logger; import com.p4square.grow.backend.GrowBackend; import com.p4square.grow.backend.db.CassandraDatabase; +import com.p4square.grow.model.Score; + /** * * @author Jesse Morgan <jesse@jesterpm.net> |