Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.sakaiproject.tool.assessment.samlite.impl.SamLiteServiceImpl Maven / Gradle / Ivy
/**
* Copyright (c) 2007-2016 The Apereo Foundation
*
* Licensed under the Educational Community 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://opensource.org/licenses/ecl2
*
* 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 org.sakaiproject.tool.assessment.samlite.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.xmlbeans.XmlOptions;
import org.imsglobal.xsd.imsQtiasiv1P2.AssessfeedbackType;
import org.imsglobal.xsd.imsQtiasiv1P2.AssessmentType;
import org.imsglobal.xsd.imsQtiasiv1P2.AssessmentcontrolType;
import org.imsglobal.xsd.imsQtiasiv1P2.ConditionvarType;
import org.imsglobal.xsd.imsQtiasiv1P2.DecvarType;
import org.imsglobal.xsd.imsQtiasiv1P2.DisplayfeedbackType;
import org.imsglobal.xsd.imsQtiasiv1P2.FlowMatType;
import org.imsglobal.xsd.imsQtiasiv1P2.FlowType;
import org.imsglobal.xsd.imsQtiasiv1P2.ItemType;
import org.imsglobal.xsd.imsQtiasiv1P2.ItemfeedbackType;
import org.imsglobal.xsd.imsQtiasiv1P2.ItemmetadataType;
import org.imsglobal.xsd.imsQtiasiv1P2.ItemrubricType;
import org.imsglobal.xsd.imsQtiasiv1P2.MaterialType;
import org.imsglobal.xsd.imsQtiasiv1P2.MatimageType;
import org.imsglobal.xsd.imsQtiasiv1P2.MattextType;
import org.imsglobal.xsd.imsQtiasiv1P2.OrType;
import org.imsglobal.xsd.imsQtiasiv1P2.OrderType;
import org.imsglobal.xsd.imsQtiasiv1P2.OutcomesType;
import org.imsglobal.xsd.imsQtiasiv1P2.PresentationMaterialType;
import org.imsglobal.xsd.imsQtiasiv1P2.PresentationType;
import org.imsglobal.xsd.imsQtiasiv1P2.QtimetadataType;
import org.imsglobal.xsd.imsQtiasiv1P2.QtimetadatafieldType;
import org.imsglobal.xsd.imsQtiasiv1P2.QuestestinteropDocument;
import org.imsglobal.xsd.imsQtiasiv1P2.RenderChoiceType;
import org.imsglobal.xsd.imsQtiasiv1P2.RenderFibType;
import org.imsglobal.xsd.imsQtiasiv1P2.RespconditionType;
import org.imsglobal.xsd.imsQtiasiv1P2.ResponseLabelType;
import org.imsglobal.xsd.imsQtiasiv1P2.ResponseLidType;
import org.imsglobal.xsd.imsQtiasiv1P2.ResponseStrType;
import org.imsglobal.xsd.imsQtiasiv1P2.ResprocessingType;
import org.imsglobal.xsd.imsQtiasiv1P2.RubricType;
import org.imsglobal.xsd.imsQtiasiv1P2.SectionType;
import org.imsglobal.xsd.imsQtiasiv1P2.SelectionOrderingType;
import org.imsglobal.xsd.imsQtiasiv1P2.SetvarType;
import org.imsglobal.xsd.imsQtiasiv1P2.VarequalType;
import org.sakaiproject.tool.assessment.samlite.api.Answer;
import org.sakaiproject.tool.assessment.samlite.api.Question;
import org.sakaiproject.tool.assessment.samlite.api.QuestionGroup;
import org.sakaiproject.tool.assessment.samlite.api.SamLiteService;
import org.sakaiproject.tool.assessment.services.assessment.AssessmentService;
import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentMetaData;
import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemMetaDataIfc;
import org.w3c.dom.Document;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.util.ResourceLoader;
@Slf4j
public class SamLiteServiceImpl implements SamLiteService {
public static final String DEFAULT_CHARSET = "UTF-8";
private static ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.SamLitePatternMessages");
private Pattern justQuestionPattern, startOfQuestionPattern, correctAnswerPattern;
private Pattern correctFillInPattern, answerPattern, endQuestionPattern, correctMultipleChoicePattern;
private Pattern shortEssayPattern, correctTruePattern, correctFalsePattern, unnecessaryTruePattern, unnecessaryFalsePattern;
private Pattern feedbackOKPattern,feedbackNOKPattern;
private Pattern correctfillInNumericPattern,complexNumberPattern,intervalPattern,realPattern;
private Pattern startOfQuestionNumericPattern;
private Pattern pointsPattern;
private Pattern discountPattern;
String realPatternString = "((\\+||\\-)?(\\d+((\\.|\\,)\\d+)?)((E|e)(\\-|\\+)?\\d+)?)";
private Pattern randomizePattern;
private Pattern rationalePattern;
private Pattern extendedMatchingCorrectAnswersPattern;
public void init() {
// Initialization
startOfQuestionNumericPattern = Pattern.compile("^(\\d+\\.|\\)|\\]\\s*)", Pattern.CASE_INSENSITIVE);
correctAnswerPattern = Pattern.compile("^\\*");
correctMultipleChoicePattern = Pattern.compile("^\\*\\s*([a-z])\\.\\s*(.*)", Pattern.CASE_INSENSITIVE);
correctFillInPattern = Pattern.compile("^\\*\\s*(?!\\{)(.*)");
answerPattern = Pattern.compile("^([a-z])\\.\\s*(.*)", Pattern.CASE_INSENSITIVE);
feedbackOKPattern=Pattern.compile("^#FBOK:\\s*(.*)$");
feedbackNOKPattern=Pattern.compile("^#FBNOK:\\s*(.*)$");
// REGEX: ^(\d+\.+ ).*\[[a-z[ ,]]*\].* - start with digits point space then string containing brackets with [a-z] commas or spaces
extendedMatchingCorrectAnswersPattern = Pattern.compile("^(\\d+\\.+ ).*\\[[a-z[ ,]]*\\].*", Pattern.CASE_INSENSITIVE);
correctfillInNumericPattern = Pattern.compile("^\\*\\{(.*)\\}");
complexNumberPattern = Pattern.compile("^\\*\\{"+realPatternString+"(\\s*)(\\+||\\-)(\\s*)"+realPatternString+"(i|I)}");
intervalPattern = Pattern.compile("^\\*\\{(\\s*)"+realPatternString+"(\\s*)(\\|)(\\s*)"+realPatternString+"(\\s*)}");
realPattern = Pattern.compile("^\\*\\{"+realPatternString+"}");
}
public Question saveLast(QuestionGroup questionGroup, Question question) {
if (null != question) {
// Short essay questions don't have any answer, so it's the default type
if (Question.UNDEFINED_QUESTION == question.getQuestionType())
question.setQuestionType(Question.SHORT_ESSAY_QUESTION);
// If it doesn't have points yet, it's not going to get any
if (!question.hasPoints())
question.setQuestionPoints("0");
question.postProcessing();
questionGroup.addQuestion(question);
}
return new Question();
}
private String getPoints(String line) {
Matcher pointsMatcher = pointsPattern.matcher(line);
String points = "";
if (pointsMatcher.find())
points = pointsMatcher.group(1);
return points;
}
private String stripPoints(String line) {
Matcher pointsMatcher = pointsPattern.matcher(line);
StringBuffer sb = new StringBuffer();
while (pointsMatcher.find()) {
pointsMatcher.appendReplacement(sb, "");
}
pointsMatcher.appendTail(sb);
return sb.toString();
}
private String getDiscount(String line) {
Matcher discountMatcher = discountPattern.matcher(line);
String discount = "";
if (discountMatcher.find())
discount = discountMatcher.group(1);
return discount;
}
private String stripDiscount(String line) {
Matcher discountMatcher = discountPattern.matcher(line);
StringBuffer sb = new StringBuffer();
while (discountMatcher.find()) {
discountMatcher.appendReplacement(sb, "");
}
discountMatcher.appendTail(sb);
return sb.toString();
}
private String removeMatchedPattern(Matcher m) {
StringBuffer buffer = new StringBuffer();
m.appendReplacement(buffer, "");
m.appendTail(buffer);
return buffer.toString();
}
public QuestionGroup parse(String name, String description, String data) {
String stQuestion = rb.getString("question");
startOfQuestionPattern = Pattern.compile("^(" + stQuestion + "\\s*\\d*\\s*)", Pattern.CASE_INSENSITIVE);
String stPoints = rb.getString("points");
pointsPattern = Pattern.compile("\\((\\d*\\.?\\d*)\\s+" + stPoints + "\\)", Pattern.CASE_INSENSITIVE);
String stDiscount = rb.getString("discount");
discountPattern = Pattern.compile("\\((\\d*\\.?\\d*)\\s+" + stDiscount + "\\)", Pattern.CASE_INSENSITIVE);
String stSaveAnswer = rb.getString("save_answer");
endQuestionPattern = Pattern.compile("^" + stSaveAnswer, Pattern.CASE_INSENSITIVE);
String stTrue = rb.getString("true");
String stFalse = rb.getString("false");
correctTruePattern = Pattern.compile("^\\*\\s*" + stTrue + "$");
correctFalsePattern = Pattern.compile("^\\*\\s*" + stFalse + "$");
unnecessaryTruePattern = Pattern.compile("^" + stTrue + "$");
unnecessaryFalsePattern = Pattern.compile("^" + stFalse + "$");
String txtRandomize = rb.getString("randomize", "#randomize");
randomizePattern = Pattern.compile("^" + txtRandomize + "$", Pattern.CASE_INSENSITIVE);
String txtRationale = rb.getString("rationale", "#rationale");
rationalePattern = Pattern.compile("^" + txtRationale + "$", Pattern.CASE_INSENSITIVE);
QuestionGroup questionGroup = new QuestionGroup(name, description);
String cleanData = data;
String[] lines = cleanData.split("\\n");
Question question = null;
int questionNumber = 1;
for (int i=0;i "))
lines[i] = lines[i].replaceAll(" ", "").replace('\r', ' ');
String line = lines[i].trim();
if (null != line && !"".equals(line)) {
Matcher startOfQuestionMatcher = startOfQuestionPattern.matcher(line);
Matcher startOfQuestionNumericMatcher = startOfQuestionNumericPattern.matcher(line);
Matcher pointsMatcher = pointsPattern.matcher(line);
Matcher discountMatcher = discountPattern.matcher(line);
Matcher extendedMatchingCorrectAnswersMatcher = extendedMatchingCorrectAnswersPattern.matcher(line);
// The question can begin with the word 'Question'
boolean isQuestionStart = startOfQuestionMatcher.find();
// Or it can begin with a number followed by a delimitor
boolean isQuestionNumericStart = startOfQuestionNumericMatcher.find();
// Some users may prefer to delineate questions with just the points line
boolean isJustPoints = pointsMatcher.find();
// Some users may want to specify the discount line
boolean isJustDiscount = discountMatcher.find();
boolean isEMICorrectAnswerLine = extendedMatchingCorrectAnswersMatcher.find();
if (!isEMICorrectAnswerLine && (isQuestionStart || isQuestionNumericStart || isJustPoints || isJustDiscount)) {
question = saveLast(questionGroup, question);
if (isQuestionStart)
line = removeMatchedPattern(startOfQuestionMatcher);
else if (isQuestionNumericStart)
line = removeMatchedPattern(startOfQuestionNumericMatcher);
String points = getPoints(line);
question.setQuestionPoints(points);
String discount = getDiscount(line);
question.setQuestionDiscount(discount);
String questionText = stripDiscount(stripPoints(line));
question.append(questionText.trim());
// Don't bother looking at what the user enters for question numbers, since they
// could introduce errors -- we're going to number by order of questions
question.setQuestionNumber(questionNumber);
questionNumber++;
} else if (null != question)
parseLine(question, line);
}
}
// Make sure we get that last question
if (null != question)
saveLast(questionGroup, question);
return questionGroup;
}
private void parseLine(Question question, String line) {
boolean isEndOfQuestion = endQuestionPattern.matcher(line).find();
boolean isCorrectAnswer = correctAnswerPattern.matcher(line).lookingAt();
Matcher answerMatcher = answerPattern.matcher(line);
boolean isAnswer = answerMatcher.find();
boolean isEmptyTrue = unnecessaryTruePattern.matcher(line).find();
boolean isEmptyFalse = unnecessaryFalsePattern.matcher(line).find();
Matcher feedbackOKMatcher = feedbackOKPattern.matcher(line);
boolean hasfeedbackOK = feedbackOKMatcher.find();
Matcher feedbackNOKMatcher = feedbackNOKPattern.matcher(line);
boolean hasfeedbackNOK = feedbackNOKMatcher.find();
boolean randomize = randomizePattern.matcher(line).find();
boolean rationale = rationalePattern.matcher(line).find();
boolean isEMICorrectAnswer = extendedMatchingCorrectAnswersPattern.matcher(line).find();
if (isEndOfQuestion) {
// Do nothing, we just want to ignore this line
} else if (isAnswer) {
question.addAnswer(answerMatcher.group(1), answerMatcher.group(2), false);
} else if (isEMICorrectAnswer) {
question.setQuestionType(Question.EXTENDED_MATCHING_ITEMS_QUESTION);
String answerId = line.substring(0, line.indexOf("."));
String questionAnswers = (line.substring(line.indexOf(".")+1)).trim();
question.addAnswer(answerId, questionAnswers, true);
} else if (isCorrectAnswer) {
Matcher multipleChoiceMatcher = correctMultipleChoicePattern.matcher(line);
boolean isMC = multipleChoiceMatcher.find();
Matcher fillInMatcher = correctFillInPattern.matcher(line);
boolean isFI = fillInMatcher.find();
boolean isTrue = correctTruePattern.matcher(line).find();
boolean isFalse = correctFalsePattern.matcher(line).find();
Matcher fillInNumericMatcher = correctfillInNumericPattern.matcher(line);
boolean isFillInNumeric = fillInNumericMatcher.find();
if (isMC) {
String earlierCorrectAnswer = question.getCorrectAnswer();
boolean hasOneCorrectAnswerAlready = (null != earlierCorrectAnswer && !"".equals(earlierCorrectAnswer.trim()));
question.setCorrectAnswer(multipleChoiceMatcher.group(1));
question.addAnswer(multipleChoiceMatcher.group(1), multipleChoiceMatcher.group(2), true);
if (hasOneCorrectAnswerAlready)
question.setQuestionType(Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION);
else
question.setQuestionType(Question.MULTIPLE_CHOICE_QUESTION);
} else if (isTrue) {
question.addAnswer("A", "True", true);
question.addAnswer("B", "False", false);
question.setQuestionType(Question.TRUE_FALSE_QUESTION);
question.setCorrectAnswer("True");
} else if (isFalse) {
question.addAnswer("A", "True", false);
question.addAnswer("B", "False", true);
question.setQuestionType(Question.TRUE_FALSE_QUESTION);
question.setCorrectAnswer("False");
} else if (isFI) {
question.setCorrectAnswer(fillInMatcher.group(1));
question.setQuestionType(Question.FILL_IN_THE_BLANK_QUESTION);
} else if (isFillInNumeric) {
String correctAnswer = fillInNumericMatcher.group(1);
if(isValidNumericResponse(line))
question.setCorrectAnswer(correctAnswer);
question.setQuestionType(Question.FILL_IN_NUMERIC_QUESTION);
}
} else if (isEmptyTrue || isEmptyFalse) {
// Do nothing, since the 'correct' true or false answer is all we need.
} else if (hasfeedbackOK) {
question.setFeedbackOK(feedbackOKMatcher.group(1));
} else if (hasfeedbackNOK) {
question.setFeedbackNOK(feedbackNOKMatcher.group(1));
} else if (randomize) {
if (question.getQuestionType() == Question.MULTIPLE_CHOICE_QUESTION ||
question.getQuestionType() == Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION) {
question.setRandomize(randomize);
}
} else if (rationale) {
if (question.getQuestionType() == Question.MULTIPLE_CHOICE_QUESTION ||
question.getQuestionType() == Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION ||
question.getQuestionType() == Question.TRUE_FALSE_QUESTION) {
question.setRationale(rationale);
}
}
else {
// If we didn't match anything, then assume it's just part of the question text
question.append(line);
}
}
public Document createDocument(QuestionGroup questionGroup) {
log.debug("Creating a new qti document with the following name: " + questionGroup.getName());
QuestestinteropDocument document = createQTIDocument(questionGroup);
XmlOptions options = new XmlOptions();
options.setSavePrettyPrintIndent(4);
options.setSavePrettyPrint();
options.setUseDefaultNamespace();
Map prefixes = new HashMap();
prefixes.put("", "http://www.imsglobal.org/xsd/ims_qtiasiv1p2");
options.setSaveImplicitNamespaces(prefixes);
InputStream inputStream = null;
try {
inputStream = document.newInputStream(options);
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(inputStream);
return doc;
} catch (ParserConfigurationException pce) {
log.error("Unable to parse quiz document ", pce);
} catch (IOException ioe) {
log.error("Low-level IOException caught reading quiz document ", ioe);
} catch (Exception qse) {
log.error("Unable to save this quiz as an imported assessment ", qse);
} finally {
if (null != inputStream) {
try { inputStream.close(); } catch (IOException ioe) { log.warn("Unimportant ioe"); }
}
}
return null;
}
public QuestestinteropDocument createQTIDocument(QuestionGroup questionGroup) {
// Create a new instance of the document object
QuestestinteropDocument doc = QuestestinteropDocument.Factory.newInstance();
// Add a Questestinterop object
doc.addNewQuestestinterop();
// Add an assessment object
doc.getQuestestinterop().addNewAssessment();
// Grab the assessment in a local var
AssessmentType assessment = doc.getQuestestinterop().getAssessment();
assessment.setTitle(questionGroup.getName());
// There's a bunch of metadata that we pre-populate here
addAssessmentMetadata(assessment);
// Now we're getting into the necessary xml fragments that make up the QTI schema
AssessmentcontrolType assessmentControl = assessment.addNewAssessmentcontrol();
assessmentControl.setFeedbackswitch(AssessmentcontrolType.Feedbackswitch.YES);
assessmentControl.setHintswitch(AssessmentcontrolType.Hintswitch.YES);
assessmentControl.setSolutionswitch(AssessmentcontrolType.Solutionswitch.YES);
assessmentControl.setView(AssessmentcontrolType.View.ALL);
RubricType rubric = assessment.addNewRubric();
buildMattext(rubric.addNewMaterial().addNewMattext());
PresentationMaterialType presentationMaterial = assessment.addNewPresentationMaterial();
FlowMatType pFlowMat = presentationMaterial.addNewFlowMat();
pFlowMat.setClass1("Block");
buildMattext(pFlowMat.addNewMaterial().addNewMattext(), questionGroup.getDescription());
AssessfeedbackType assessFeedback = assessment.addNewAssessfeedback();
assessFeedback.setIdent("Feedback");
assessFeedback.setTitle("Feedback");
assessFeedback.setView(AssessfeedbackType.View.ALL);
FlowMatType afFlowMat = assessFeedback.addNewFlowMat();
buildMattext(afFlowMat.addNewMaterial().addNewMattext());
// Add the section
SectionType section = assessment.addNewSection();
section.setIdent("Multiple Choice Questions");
QtimetadataType sectionMetaData = section.addNewQtimetadata();
buildMetaDataField(sectionMetaData, "SECTION_OBJECTIVE", "");
buildMetaDataField(sectionMetaData, "SECTION_KEYWORD", "");
buildMetaDataField(sectionMetaData, "SECTION_RUBRIC", "");
PresentationMaterialType sectionPresentationMaterial = section.addNewPresentationMaterial();
FlowMatType spFlowMat = sectionPresentationMaterial.addNewFlowMat();
spFlowMat.setClass1("Block");
buildMattext(spFlowMat.addNewMaterial().addNewMattext());
buildEmptyMaterialImage(spFlowMat.addNewMaterial().addNewMatimage());
SelectionOrderingType selectionOrdering = section.addNewSelectionOrdering();
selectionOrdering.setSequenceType("Normal");
OrderType order = selectionOrdering.addNewOrder();
order.setOrderType("Sequential");
// Now, loop through the questions and add to the qti section object
if (null != questionGroup.getQuestions()) {
for (Iterator it = questionGroup.getQuestions().iterator();it.hasNext();) {
Question question = (Question)it.next();
processQuestion(section, question);
}
}
return doc;
}
private void buildMetaDataField(QtimetadataType metadata, String label, String entry) {
QtimetadatafieldType field = metadata.addNewQtimetadatafield();
field.setFieldlabel(label);
field.setFieldentry(entry);
}
private void addAssessmentMetadata(AssessmentType assessment) {
QtimetadataType metadata = assessment.addNewQtimetadata();
AssessmentService service = new AssessmentService();
List metadataList = service.getDefaultMetaDataSet();
Iterator iter = metadataList.iterator();
String automaticSubmissionEditable = "true";
while (iter.hasNext()) {
AssessmentMetaData mData = (AssessmentMetaData) iter.next();
if ("automaticSubmission_isInstructorEditable".equals((String) mData.getLabel())) {
automaticSubmissionEditable = (String) mData.getEntry();
}
else {
String label = (String) mData.getLabel();
String entry = (String) mData.getEntry();
buildMetaDataField(metadata, label, entry);
}
}
boolean autoSubmitEnabled = ServerConfigurationService.getBoolean("samigo.autoSubmit.enabled", false);
if (!autoSubmitEnabled) {
buildMetaDataField(metadata, "automaticSubmission_isInstructorEditable", "false");
}
else {
buildMetaDataField(metadata, "automaticSubmission_isInstructorEditable", automaticSubmissionEditable);
}
}
private void processQuestion(SectionType section, Question question) {
log.debug("Processing a question");
switch (question.getQuestionType()) {
case Question.MULTIPLE_CHOICE_QUESTION:
processMultipleChoiceQuestion(section, question);
break;
case Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION:
processMultipleChoiceMultipleAnswerQuestion(section, question);
break;
case Question.FILL_IN_THE_BLANK_QUESTION:
processFillInQuestion(section, question);
break;
case Question.FILL_IN_NUMERIC_QUESTION:
processFillInNumericQuestion(section, question);
break;
case Question.SHORT_ESSAY_QUESTION:
processShortEssayQuestion(section, question);
break;
case Question.TRUE_FALSE_QUESTION:
processTrueFalseQuestion(section, question);
break;
case Question.EXTENDED_MATCHING_ITEMS_QUESTION:
processExtendedMatchingItemsQuestion(section, question);
break;
default:
// TODO: Notify the user that this question didn't work...
};
}
private void buildMattext(MattextType mattext) {
mattext.setCharset(DEFAULT_CHARSET);
mattext.setTexttype("text/plain");
}
private void buildMattext(MattextType mattext, String value) {
buildMattext(mattext);
mattext.setStringValue(cdata(value));
}
private String cdata(String value) {
return value;
//new StringBuffer().append("").toString();
}
private void buildEmptyMaterialImage(MatimageType matImage) {
matImage.setEmbedded("base64");
matImage.setImagtype("text/html");
}
private void buildItemFeedback(ItemType item, String identity) {
ItemfeedbackType ifeedback = item.addNewItemfeedback();
ifeedback.setIdent(identity);
ifeedback.setView(ItemfeedbackType.View.ALL);
FlowMatType ifflow = ifeedback.addNewFlowMat();
ifflow.setClass1("Block");
buildMattext(ifflow.addNewMaterial().addNewMattext());
buildEmptyMaterialImage(ifflow.addNewMaterial().addNewMatimage());
}
private void buildItemFeedback(ItemType item, String identity, String feedback) {
ItemfeedbackType ifeedback = item.addNewItemfeedback();
ifeedback.setIdent(identity);
ifeedback.setView(ItemfeedbackType.View.ALL);
FlowMatType ifflow = ifeedback.addNewFlowMat();
ifflow.setClass1("Block");
buildMattext(ifflow.addNewMaterial().addNewMattext(),feedback);
buildEmptyMaterialImage(ifflow.addNewMaterial().addNewMatimage());
}
private void buildPresentationAndResponseLid(ItemType item, Question question, String label,
String respLidId, ResponseLidType.Rcardinality.Enum rCardinality) {
PresentationType presentation = item.addNewPresentation();
presentation.setLabel(label);
FlowType flow = presentation.addNewFlow();
flow.setClass1("Block");
MaterialType material = flow.addNewMaterial();
buildMattext(material.addNewMattext(), cdata(question.getQuestion()));
MaterialType material2 = flow.addNewMaterial();
buildMattext(material2.addNewMattext());
// Only for multiple choice
if (Question.MULTIPLE_CHOICE_QUESTION == question.getQuestionType() ||
Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION == question.getQuestionType()) {
MatimageType matImage = material2.addNewMatimage();
matImage.setEmbedded("base64");
matImage.setImagtype("text/html");
matImage.setUri("");
}
ResponseLidType responseLid = flow.addNewResponseLid();
responseLid.setIdent(respLidId);
responseLid.setRcardinality(rCardinality);
responseLid.setRtiming(ResponseLidType.Rtiming.NO);
RenderChoiceType renderChoice = responseLid.addNewRenderChoice();
renderChoice.setShuffle(RenderChoiceType.Shuffle.NO);
char c = 'A';
for (Iterator it = question.getAnswers().iterator();it.hasNext();) {
Answer answer = (Answer)it.next();
ResponseLabelType responseLabel = renderChoice.addNewResponseLabel();
responseLabel.setIdent(String.valueOf(c));
responseLabel.setRarea(ResponseLabelType.Rarea.ELLIPSE);
responseLabel.setRrange(ResponseLabelType.Rrange.EXACT);
responseLabel.setRshuffle(ResponseLabelType.Rshuffle.YES);
MaterialType mat = responseLabel.addNewMaterial();
MattextType text = mat.addNewMattext();
text.setCharset(DEFAULT_CHARSET);
text.setTexttype("text/plain");
text.setStringValue(cdata(answer.getText()));
MaterialType m2 = responseLabel.addNewMaterial();
MatimageType mi = m2.addNewMatimage();
mi.setEmbedded("base64");
mi.setImagtype("text/html");
mi.setUri("");
c++;
}
}
private void addResponseLid(FlowType flow, Question question, boolean isMultipleAnswer) {
ResponseLidType responseLid = flow.addNewResponseLid();
responseLid.setIdent("MCSC");
if (isMultipleAnswer)
responseLid.setRcardinality(ResponseLidType.Rcardinality.MULTIPLE);
else
responseLid.setRcardinality(ResponseLidType.Rcardinality.SINGLE);
responseLid.setRtiming(ResponseLidType.Rtiming.NO);
RenderChoiceType renderChoice = responseLid.addNewRenderChoice();
renderChoice.setShuffle(RenderChoiceType.Shuffle.NO);
char c = 'A';
for (Iterator it = question.getAnswers().iterator();it.hasNext();) {
Answer answer = (Answer)it.next();
ResponseLabelType responseLabel = renderChoice.addNewResponseLabel();
responseLabel.setIdent(String.valueOf(c));
responseLabel.setRarea(ResponseLabelType.Rarea.ELLIPSE);
responseLabel.setRrange(ResponseLabelType.Rrange.EXACT);
responseLabel.setRshuffle(ResponseLabelType.Rshuffle.YES);
MaterialType mat = responseLabel.addNewMaterial();
MattextType text = mat.addNewMattext();
text.setCharset(DEFAULT_CHARSET);
text.setTexttype("text/plain");
text.setStringValue(cdata(answer.getText()));
MaterialType m2 = responseLabel.addNewMaterial();
MatimageType mi = m2.addNewMatimage();
mi.setEmbedded("base64");
mi.setImagtype("text/html");
mi.setUri("");
c++;
}
}
private void addRespProcessing(ItemType item, Question question, String respident) {
ResprocessingType resProcessing = item.addNewResprocessing();
DecvarType decvar = resProcessing.addNewOutcomes().addNewDecvar();
decvar.setDefaultval("0");
decvar.setMaxvalue(question.getQuestionPoints());
if (Question.MULTIPLE_CHOICE_MULTIPLE_ANSWER_QUESTION != question.getQuestionType())
decvar.setMinvalue(question.getQuestionDiscount());
else
decvar.setMinvalue("0");
decvar.setVarname("SCORE");
decvar.setVartype(DecvarType.Vartype.INTEGER);
char alpha = 'A';
if (null != question.getAnswers()) {
for (Iterator it = question.getAnswers().iterator();it.hasNext();) {
Answer answer = (Answer)it.next();
String response = answer.isCorrect() ? "Correct" : "InCorrect";
RespconditionType respCondition = resProcessing.addNewRespcondition();
respCondition.setContinue(RespconditionType.Continue.NO);
ConditionvarType conditionVar = respCondition.addNewConditionvar();
VarequalType varEqual = conditionVar.addNewVarequal();
varEqual.setCase(VarequalType.Case.YES);
varEqual.setRespident(respident);
varEqual.setStringValue(String.valueOf(alpha));
SetvarType setVar = respCondition.addNewSetvar();
setVar.setAction(SetvarType.Action.ADD);
setVar.setVarname("SCORE");
setVar.setStringValue("0.0");
DisplayfeedbackType feedback1 = respCondition.addNewDisplayfeedback();
feedback1.setFeedbacktype(DisplayfeedbackType.Feedbacktype.RESPONSE);
feedback1.setLinkrefid(response);
DisplayfeedbackType feedback2 = respCondition.addNewDisplayfeedback();
feedback2.setFeedbacktype(DisplayfeedbackType.Feedbacktype.RESPONSE);
feedback2.setLinkrefid("AnswerFeedback");
feedback2.setStringValue(cdata(""));
alpha++;
}
}
}
private void processExtendedMatchingItemsQuestion(SectionType section, Question question) {
ItemType item = section.addNewItem();
item.setTitle(question.getQuestionTypeAsString());
ItemmetadataType itemMetaData = item.addNewItemmetadata();
QtimetadataType qtiMetaData = itemMetaData.addNewQtimetadata();
buildMetaDataField(qtiMetaData, "qmd_itemtype", question.getQuestionTypeAsString());
buildMetaDataField(qtiMetaData, "TEXT_FORMAT", "HTML");
buildMetaDataField(qtiMetaData, "hasRationale", "False");
ItemrubricType itemRubric = item.addNewItemrubric();
MattextType mattext = itemRubric.addNewMaterial().addNewMattext();
mattext.setCharset("UTF-8");
mattext.setTexttype("text/plain");
buildPresentationAndResponseLid(item, question, "Resp001", "EMIQ", ResponseLidType.Rcardinality.MULTIPLE);
addRespProcessing(item, question, "EMIQ");
int numberOfAnswers = question.getAnswers().size();
char c = 'A';
for (int i=0;i