/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-archive/sam-handlers/src/java/org/sakaiproject/importer/impl/handlers/SamigoPoolHandler.java $
* $Id: SamigoPoolHandler.java 107562 2012-04-25 11:53:21Z david.horwitz@uct.ac.za $
***********************************************************************************
*
* Copyright (c) 2006, 2007, 2008 The Sakai 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://www.opensource.org/licenses/ECL-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 org.sakaiproject.importer.impl.handlers;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sakaiproject.importer.api.HandlesImportable;
import org.sakaiproject.importer.api.Importable;
import org.sakaiproject.importer.impl.importables.AssessmentAnswer;
import org.sakaiproject.importer.impl.importables.AssessmentQuestion;
import org.sakaiproject.importer.impl.importables.QuestionPool;
import org.sakaiproject.tool.assessment.data.dao.assessment.Answer;
import org.sakaiproject.tool.assessment.data.dao.assessment.AnswerFeedback;
import org.sakaiproject.tool.assessment.data.dao.assessment.ItemText;
import org.sakaiproject.tool.assessment.facade.ItemFacade;
import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade;
import org.sakaiproject.tool.assessment.services.ItemService;
import org.sakaiproject.tool.assessment.services.QuestionPoolService;
import org.sakaiproject.tool.cover.SessionManager;
public class SamigoPoolHandler implements HandlesImportable {
// Samigo identifies each question type with an int
public static final int TRUE_FALSE = 4;
public static final int FILL_BLANK = 8;
public static final int MATCHING = 9;
private QuestionPoolService qps = new QuestionPoolService();
private ItemService itemService = new ItemService();
public boolean canHandleType(String typeName) {
return "sakai-question-pool".equals(typeName);
}
public void handle(Importable thing, String siteId) {
QuestionPool importPool = (QuestionPool)thing;
QuestionPoolFacade pool = new QuestionPoolFacade();
pool.setOwnerId(SessionManager.getCurrentSessionUserId());
pool.setTitle(importPool.getTitle());
pool.setDescription(importPool.getDescription());
// have no idea what the magic number 30 is for, but Samigo used it when I created a question pool in the tool
pool.setAccessTypeId(Long.valueOf(30));
Set questionItems = new HashSet();
questionItems.addAll(doQuestions(importPool.getEssayQuestions(), siteId));
questionItems.addAll(doQuestions(importPool.getFillBlankQuestions(), siteId));
questionItems.addAll(doQuestions(importPool.getMatchQuestions(), siteId));
questionItems.addAll(doQuestions(importPool.getMultiAnswerQuestions(), siteId));
questionItems.addAll(doQuestions(importPool.getMultiChoiceQuestions(), siteId));
// Samigo doesn't have native support for ordering questions. Maybe there's a workaround?
// questionItems.addAll(doQuestions(importPool.getOrderingQuestions()));
questionItems.addAll(doQuestions(importPool.getTrueFalseQuestions(), siteId));
QuestionPoolFacade savedPool = qps.savePool(pool);
Object[] questionItemsArray = questionItems.toArray();
Arrays.sort(questionItemsArray, new Comparator() {
public int compare(Object o1, Object o2) {
Integer i1 = ((ItemFacade)o1).getSequence();
Integer i2 = ((ItemFacade)o2).getSequence();
return i1.compareTo(i2);
}
});
for (int i = 0;i < questionItemsArray.length; i++) {
ItemFacade item = (ItemFacade)questionItemsArray[i];
item.setSequence(Integer.valueOf(i + 1));
qps.addItemToPool(item.getItemIdString(),savedPool.getQuestionPoolId());
}
}
private Collection doQuestions(List questions, String siteId) {
AssessmentQuestion importableQuestion;
AssessmentAnswer importableAnswer;
AssessmentAnswer importableChoice;
Collection rv = new Vector();
ItemFacade itemFacade = null;
String questionTextString = null;
ItemText text = null;
HashSet textSet = null;
Answer answer = null;
HashSet answerSet = null;
AnswerFeedback answerFeedback = null;
HashSet answerFeedbackSet = null;
int questionCount = 0;
for(Iterator i = questions.iterator();i.hasNext();) {
importableQuestion = (AssessmentQuestion)i.next();
questionCount++;
Set correctAnswerIDs = importableQuestion.getCorrectAnswerIDs();
itemFacade = new ItemFacade();
textSet = new HashSet();
questionTextString = contextualizeUrls(importableQuestion.getQuestionText(), siteId);
if (importableQuestion.getQuestionType() == SamigoPoolHandler.MATCHING) {
itemFacade.setInstruction(questionTextString);
Collection answers = importableQuestion.getAnswers().values();
Collection choices = importableQuestion.getChoices().values();
int answerIndex = 1;
for (Iterator j = answers.iterator();j.hasNext();) {
importableAnswer = (AssessmentAnswer)j.next();
text = new ItemText();
text.setSequence(Long.valueOf(answerIndex));
answerIndex++;
text.setText(contextualizeUrls(importableAnswer.getAnswerText(), siteId));
answerSet = new HashSet();
int choiceIndex = 1;
for (Iterator k = choices.iterator();k.hasNext();) {
importableChoice = (AssessmentAnswer)k.next();
answer = new Answer();
answer.setItem(itemFacade.getData());
answer.setItemText(text);
answer.setSequence(new Long(choiceIndex));
choiceIndex++;
// set label A, B, C, D, etc. on answer based on its sequence number
answer.setLabel(new Character((char)(64 + choiceIndex)).toString());
answer.setText(contextualizeUrls(importableChoice.getAnswerText(), siteId));
answer.setIsCorrect(Boolean.valueOf(importableAnswer.getChoiceId().equals(importableChoice.getAnswerId())));
answerSet.add(answer);
}
text.setAnswerSet(answerSet);
text.setItem(itemFacade.getData());
textSet.add(text);
}
} else {
text = new ItemText();
text.setSequence(new Long(1));
text.setText(questionTextString);
answerSet = new HashSet();
answerFeedbackSet = new HashSet();
Collection answers = importableQuestion.getAnswers().values();
StringBuilder answerBuffer = new StringBuilder();
for (Iterator j = answers.iterator();j.hasNext();) {
importableAnswer = (AssessmentAnswer)j.next();
answerBuffer.append(importableAnswer.getAnswerText());
if (j.hasNext()) answerBuffer.append("|");
String answerId = importableAnswer.getAnswerId();
answer = new Answer();
answer.setItem(itemFacade.getData());
answer.setItemText(text);
answer.setSequence(new Long(importableAnswer.getPosition()));
// set label A, B, C, D, etc. on answer based on its sequence number
answer.setLabel(new Character((char)(64 + importableAnswer.getPosition())).toString());
if (importableQuestion.getQuestionType() == SamigoPoolHandler.TRUE_FALSE) {
// Samigo only understands True/False answers in lower case
answer.setText(importableAnswer.getAnswerText().toLowerCase());
} else if (importableQuestion.getQuestionType() == SamigoPoolHandler.FILL_BLANK) {
if (j.hasNext()) continue;
answer.setText(answerBuffer.toString());
Pattern pattern = Pattern.compile("_+|<<.*>>");
Matcher matcher = pattern.matcher(questionTextString);
if (matcher.find()) questionTextString = questionTextString.replaceFirst(matcher.group(),"{}");
text.setText(questionTextString);
answer.setSequence(new Long(1));
} else {
answer.setText(contextualizeUrls(importableAnswer.getAnswerText(), siteId));
}
answer.setIsCorrect(Boolean.valueOf(correctAnswerIDs.contains(answerId)));
answerSet.add(answer);
}
text.setAnswerSet(answerSet);
text.setItem(itemFacade.getData());
textSet.add(text);
}
itemFacade.setItemTextSet(textSet);
itemFacade.setCorrectItemFeedback(importableQuestion.getFeedbackWhenCorrect());
itemFacade.setInCorrectItemFeedback(importableQuestion.getFeedbackWhenIncorrect());
itemFacade.setTypeId(new Long(importableQuestion.getQuestionType()));
itemFacade.setScore(importableQuestion.getPointValue());
itemFacade.setSequence(importableQuestion.getPosition());
// status is 0=inactive or 1=active
itemFacade.setStatus(Integer.valueOf(1));
itemFacade.setHasRationale(Boolean.FALSE);
itemFacade.setCreatedBy(SessionManager.getCurrentSessionUserId());
itemFacade.setCreatedDate(new java.util.Date());
itemFacade.setLastModifiedBy(SessionManager.getCurrentSessionUserId());
itemFacade.setLastModifiedDate(new java.util.Date());
itemService.saveItem(itemFacade);
rv.add(itemFacade);
}
return rv;
}
protected String contextualizeUrls(String text, String siteId) {
if (text == null) return null;
// this regular expression is specifically looking for image urls
// but only urls that are not absolute (i.e., do not start "http")
String anyRelativeUrl = "src=\"(?!http)/?";
return text.replaceAll(anyRelativeUrl, "src=\"/access/content/group/"
+ siteId + "/TQimages/"); }
}