/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-archive/sam-handlers/src/java/org/sakaiproject/importer/impl/handlers/SamigoAssessmentHandler.java $ * $Id: SamigoAssessmentHandler.java 106519 2012-04-04 07:12:37Z 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.Date; 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.osid.assessment.AssessmentException; import org.sakaiproject.importer.api.HandlesImportable; import org.sakaiproject.importer.api.Importable; import org.sakaiproject.importer.impl.importables.Assessment; import org.sakaiproject.importer.impl.importables.AssessmentAnswer; import org.sakaiproject.importer.impl.importables.AssessmentQuestion; 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.AssessmentData; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemText; import org.sakaiproject.tool.assessment.facade.AssessmentFacade; import org.sakaiproject.tool.assessment.facade.ItemFacade; import org.sakaiproject.tool.assessment.facade.SectionFacade; import org.sakaiproject.tool.assessment.services.ItemService; import org.sakaiproject.tool.assessment.services.SectionService; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionDataIfc; public class SamigoAssessmentHandler 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; public static final String QUIZ_TYPE = "62"; public static final String QUIZ_TEMPLATE = "3"; private AssessmentService as = new AssessmentService(); private ItemService itemService = new ItemService(); public boolean canHandleType(String typeName) { return "sakai-assessment".equals(typeName); } public void handle(Importable thing, String siteId) { Assessment importAssessment = (Assessment)thing; AssessmentFacade assessment = null; try { assessment = as.createAssessmentWithoutDefaultSection( importAssessment.getTitle(), importAssessment.getDescription(), SamigoAssessmentHandler.QUIZ_TYPE, SamigoAssessmentHandler.QUIZ_TEMPLATE, siteId); AssessmentData data = new AssessmentData(new Long(SamigoAssessmentHandler.QUIZ_TEMPLATE), importAssessment.getTitle(), new Date()); data.setTypeId(new Long(SamigoAssessmentHandler.QUIZ_TYPE)); data.setTitle(importAssessment.getTitle()); data.setDescription(importAssessment.getDescription()); data.setAssessmentTemplateId(new Long(SamigoAssessmentHandler.QUIZ_TEMPLATE)); data.setCreatedBy(SessionManager.getCurrentSessionUserId()); data.setLastModifiedBy(SessionManager.getCurrentSessionUserId()); data.setLastModifiedDate(new Date()); // have no idea what the magic number 30 is for, but Samigo used it when I created a question pool in the tool data.setStatus(Integer.valueOf(1)); data.setIsTemplate(Boolean.valueOf(false)); data.setCreatedDate(new Date()); Set questionItems = new HashSet(); questionItems.addAll(doQuestions(importAssessment.getEssayQuestions(), siteId)); questionItems.addAll(doQuestions(importAssessment.getFillBlankQuestions(), siteId)); questionItems.addAll(doQuestions(importAssessment.getMatchQuestions(), siteId)); questionItems.addAll(doQuestions(importAssessment.getMultiAnswerQuestions(), siteId)); questionItems.addAll(doQuestions(importAssessment.getMultiChoiceQuestions(), siteId)); // Samigo doesn't have native support for ordering questions. Maybe there's a workaround? // questionItems.addAll(doQuestions(importPool.getOrderingQuestions())); questionItems.addAll(doQuestions(importAssessment.getTrueFalseQuestions(), siteId)); Set sectionSet = new HashSet(); SectionFacade section = new SectionFacade(); section.setTypeId(Long.valueOf(21)); section.setCreatedBy(SessionManager.getCurrentSessionUserId()); section.setCreatedDate(new Date()); section.setLastModifiedBy(SessionManager.getCurrentSessionUserId()); section.setLastModifiedDate(new Date()); section.setStatus(Integer.valueOf(1)); section.setSequence(Integer.valueOf(1)); section.setAssessmentId(assessment.getAssessmentId()); section.setAssessment(assessment); as.saveOrUpdateSection(section); 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)); item.setSection(section); section.addItem(itemService.saveItem(item)); } data.setSectionSet(sectionSet); assessment.setData(data); assessment.setSectionSet(sectionSet); as.saveAssessment(assessment); } catch (Exception e) { // error creating this assessment e.printStackTrace(); } catch (AssessmentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 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(Long.valueOf(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(new Boolean(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(Long.valueOf(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/"); } }