/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/sam/tags/samigo-2.8.3/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/qti/XMLImportBean.java $ * $Id: XMLImportBean.java 87885 2011-01-31 22:50:02Z ktsao@stanford.edu $ *********************************************************************************** * * Copyright (c) 2004, 2005, 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.osedu.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.tool.assessment.ui.bean.qti; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import org.sakaiproject.util.FormattedText; import org.sakaiproject.util.ResourceLoader; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.faces.event.ValueChangeEvent; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.service.gradebook.shared.GradebookService; import org.sakaiproject.spring.SpringBeanLocator; import org.sakaiproject.tool.assessment.contentpackaging.ImportService; import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc; import org.sakaiproject.tool.assessment.facade.AssessmentFacade; import org.sakaiproject.tool.assessment.facade.AssessmentFacadeQueries; import org.sakaiproject.tool.assessment.facade.AssessmentTemplateFacade; import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade; import org.sakaiproject.tool.assessment.integration.context.IntegrationContextFactory; import org.sakaiproject.tool.assessment.integration.helper.ifc.GradebookServiceHelper; import org.sakaiproject.tool.assessment.qti.constants.QTIVersion; import org.sakaiproject.tool.assessment.qti.util.XmlUtil; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.tool.assessment.services.qti.QTIService; import org.sakaiproject.tool.assessment.ui.bean.author.AssessmentBean; import org.sakaiproject.tool.assessment.ui.bean.author.AuthorBean; import org.sakaiproject.tool.assessment.ui.bean.author.ItemAuthorBean; import org.sakaiproject.tool.assessment.ui.bean.questionpool.QuestionPoolBean; import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; import org.w3c.dom.Document; import org.xml.sax.SAXException; /** * <p>Bean for QTI Import Data</p> */ public class XMLImportBean implements Serializable { /** Use serialVersionUID for interoperability. */ private final static long serialVersionUID = 418920360211039758L; private static Log log = LogFactory.getLog(XMLImportBean.class); private int qtiVersion; private String uploadFileName; private String importType; private String pathToData; private AuthorBean authorBean; private AssessmentBean assessmentBean; private ItemAuthorBean itemAuthorBean; private QuestionPoolBean questionPoolBean; private boolean isCP; private String importType2; private static final GradebookServiceHelper gbsHelper = IntegrationContextFactory.getInstance().getGradebookServiceHelper(); private static final boolean integrated = IntegrationContextFactory.getInstance().isIntegrated(); public XMLImportBean() { qtiVersion = QTIVersion.VERSION_1_2;//default } // put tests here... public static void main(String[] args) { //XMLImportBean XMLImportBean1 = new XMLImportBean(); } public void importAssessment(ValueChangeEvent e) { String sourceType = ContextUtil.lookupParam("sourceType"); String uploadFile = (String) e.getNewValue(); if ("2".equals(sourceType)) { if(uploadFile.toLowerCase().endsWith(".zip")) { isCP = true; importAssessment(uploadFile, true, true); } else { isCP = false; importAssessment(uploadFile, false, true); } } else { if(uploadFile.toLowerCase().endsWith(".zip")) { isCP = true; importAssessment(uploadFile,true, false); } else { isCP = false; importAssessment(uploadFile, false, false); } } } /** * Value change on upload * @param e the event */ public void importAssessment(String uploadFile, boolean isCP, boolean isRespondus) { String filename = uploadFile; String unzipLocation = null; boolean fileNotFound = false; if (isCP) { ImportService importService = new ImportService(); unzipLocation = importService.unzipImportFile(uploadFile); filename = unzipLocation + "/" + importService.getQTIFilename(); } try { processFile(filename, uploadFile, isRespondus); } catch (FileNotFoundException fnfex) { fileNotFound = true; ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorImportExport"); FacesMessage message = new FacesMessage( rb.getString("import_qti_not_found") ); FacesContext.getCurrentInstance().addMessage(null, message); } catch (Exception ex) { ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorImportExport"); FacesMessage message = new FacesMessage( rb.getString("import_err") ); FacesContext.getCurrentInstance().addMessage(null, message); } finally { boolean success = false; // remove unsuccessful file if (!fileNotFound) { log.debug("****Clean up file: "+filename); File f1 = new File(filename); success = f1.delete(); if (!success) { log.error ("Failed to delete file " + filename); } } if (isCP) { File f2 = new File(uploadFile); success = f2.delete(); if (!success) { log.error ("Failed to delete file " + uploadFile); } File f3 = new File(unzipLocation); deleteDirectory(f3); } } } /** * * @return QTI version of XML file */ public int getQtiVersion() { return qtiVersion; } /** * * @param qtiVersion QTI version of XML file */ public void setQtiVersion(int qtiVersion) { if (!QTIVersion.isValid(qtiVersion)) { throw new IllegalArgumentException("NOT Legal Qti Version."); } this.qtiVersion = qtiVersion; } /** * * @return file name and path */ public String getUploadFileName() { return uploadFileName; } /** * * @param uploadFileName file name and path */ public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } /** * A, S, I * @return type of upload */ public String getImportType() { return importType; } /** * A, S, I * @param importType A, S, or I */ public void setImportType(String importType) { this.importType = importType; } public String getImportType2() { return importType2; } /** * A, S, I * @param importType A, S, or I */ public void setImportType2(String importType2) { this.importType2 = importType2; } private void processFile(String fileName, String uploadFile, boolean isRespondus) throws Exception { itemAuthorBean.setTarget(ItemAuthorBean.FROM_ASSESSMENT); // save to assessment AssessmentService assessmentService = new AssessmentService(); // Create an assessment based on the uploaded file ArrayList failedMatchingQuestions = new ArrayList(); AssessmentFacade assessment = createImportedAssessment(fileName, qtiVersion, isRespondus, failedMatchingQuestions); if (failedMatchingQuestions.size() > 0) { String importedFilename = getImportedFilename(uploadFile); ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorImportExport"); StringBuffer sb = new StringBuffer("\""); sb.append(importedFilename); sb.append("\" "); sb.append(rb.getString("respondus_matching_err_1")); sb.append(" "); for(int i = 0; i < failedMatchingQuestions.size() - 1; i++) { sb.append(" "); sb.append(failedMatchingQuestions.get(i)); sb.append(", "); } sb.append(failedMatchingQuestions.get(failedMatchingQuestions.size() - 1)); sb.append(". "); sb.append(rb.getString("respondus_matching_err_2")); FacesMessage message = new FacesMessage(sb.toString()); FacesContext.getCurrentInstance().addMessage(null, message); } // change grading book settings if there is no gradebook in the site boolean hasGradebook = false; GradebookService g = null; if (integrated){ g = (GradebookService) SpringBeanLocator.getInstance(). getBean("org.sakaiproject.service.gradebook.GradebookService"); } try{ if (gbsHelper.isAssignmentDefined(assessment.getTitle(), g)){ hasGradebook= true; } } catch(Exception e){ log.debug("Error calling gradebookHelper"); } // gradebook options, don't know how this is supposed to work, leave alone for now if (!hasGradebook && assessment!=null){ assessment.getEvaluationModel().setToGradeBook(EvaluationModelIfc.NOT_TO_GRADEBOOK.toString()); } assessmentService.saveAssessment(assessment); // Go to editAssessment.jsp, so prepare assessmentBean assessmentBean.setAssessment(assessment); // reset in case anything hanging around authorBean.setAssessTitle(""); authorBean.setAssessmentDescription(""); authorBean.setAssessmentTypeId(""); authorBean.setAssessmentTemplateId(AssessmentTemplateFacade.DEFAULTTEMPLATE.toString()); // update core AssessmentList: get the managed bean, author and set the list ArrayList list = assessmentService.getBasicInfoOfAllActiveAssessments( AssessmentFacadeQueries.TITLE,true); Iterator iter = list.iterator(); while (iter.hasNext()) { AssessmentFacade assessmentFacade= (AssessmentFacade) iter.next(); assessmentFacade.setTitle(FormattedText.convertFormattedTextToPlaintext(assessmentFacade.getTitle())); } authorBean.setAssessments(list); } private String getImportedFilename(String filename) { String temp_filename_1 = filename.substring(filename.lastIndexOf("/") + 1); String temp_filename_2 = temp_filename_1.substring(temp_filename_1.indexOf(".")); String temp_filename_3 = temp_filename_1.substring(0, temp_filename_1.substring(0, temp_filename_1.indexOf(".")).lastIndexOf("_")); String final_filename = temp_filename_3 + temp_filename_2; return final_filename; } private void deleteDirectory(File directory) { if(directory.exists()) { File[] files = directory.listFiles(); for(int i=0; i < files.length; i++) { if(files[i].isDirectory()) { deleteDirectory(files[i]); } else { boolean success = files[i].delete(); if (!success) log.error("Delete Failed."); } } } boolean success = directory.delete(); if (!success) log.error("Delete Failed."); } /** * Create assessment from uploaded QTI XML * @param fullFileName file name and path * @param qti QTI version * @param isRespondus true/false * @return */ private AssessmentFacade createImportedAssessment(String fullFileName, int qti, boolean isRespondus, ArrayList failedMatchingQuestions) throws Exception { //trim = true so that xml processing instruction at top line, even if not. Document document = null; try { document = XmlUtil.readDocument(fullFileName, true); } catch (Exception e) { throw(e); } QTIService qtiService = new QTIService(); if (isCP) { return qtiService.createImportedAssessment(document, qti, fullFileName.substring(0, fullFileName.lastIndexOf("/")), isRespondus, failedMatchingQuestions); } else { return qtiService.createImportedAssessment(document, qti, null, isRespondus, failedMatchingQuestions); } } public AuthorBean getAuthorBean() { return authorBean; } public void setAuthorBean(AuthorBean authorBean) { this.authorBean = authorBean; } public AssessmentBean getAssessmentBean() { return assessmentBean; } public void setAssessmentBean(AssessmentBean assessmentBean) { this.assessmentBean = assessmentBean; } public ItemAuthorBean getItemAuthorBean() { return itemAuthorBean; } public void setItemAuthorBean(ItemAuthorBean itemAuthorBean) { this.itemAuthorBean = itemAuthorBean; } /** * Value change on upload * @param e the event */ public void importPoolFromQti(ValueChangeEvent e) { String uploadFile = (String) e.getNewValue(); try { processAsPoolFile(uploadFile); } catch (Exception ex) { ResourceLoader rb = new ResourceLoader("org.sakaiproject.tool.assessment.bundle.AuthorImportExport"); FacesMessage message = new FacesMessage( rb.getString("import_err") ); FacesContext.getCurrentInstance().addMessage(null, message); } } /** * Process uploaded QTI XML * assessment as question pool * @throws Exception */ private void processAsPoolFile(String uploadFile) throws Exception { itemAuthorBean.setTarget(ItemAuthorBean.FROM_QUESTIONPOOL); // save to questionpool // Get the file name String fileName = uploadFile; // Create a questionpool based on the uploaded assessment file QuestionPoolFacade questionPool = createImportedQuestionPool(fileName, qtiVersion); // remove uploaded file try{ //System.out.println("****filename="+fileName); File upload = new File(fileName); boolean success = upload.delete(); if (!success) log.error ("Failed to delete file " + fileName); } catch(Exception e){ e.printStackTrace(); } } /** * Create questionpool from uploaded QTI assessment XML * @param fullFileName file name and path * @param qti QTI version * @return * @throws Exception */ private QuestionPoolFacade createImportedQuestionPool(String fullFileName, int qti) throws Exception { //trim = true so that xml processing instruction at top line, even if not. Document document; try { document = XmlUtil.readDocument(fullFileName, true); } catch (Exception e) { throw(e); } QTIService qtiService = new QTIService(); return qtiService.createImportedQuestionPool(document, qti); } public QuestionPoolBean getQuestionPoolBean() { return questionPoolBean; } public void setQuestionPoolBean(QuestionPoolBean questionPoolBean) { this.questionPoolBean = questionPoolBean; } public String getPathToData() { return pathToData; } public void setPathToData(String pathToData) { this.pathToData = pathToData; } }