Java tutorial
/********************************************************************************** * $URL$ * $Id$ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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.tool.assessment.qti.helper; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.*; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.tool.cover.ToolManager; import org.xml.sax.SAXException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.tool.assessment.shared.api.assessment.SecureDeliveryServiceAPI; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentAccessControl; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentFeedback; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentMetaData; import org.sakaiproject.tool.assessment.data.dao.assessment.EvaluationModel; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemMetaData; import org.sakaiproject.tool.assessment.data.dao.questionpool.QuestionPoolItemData; import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentAccessControlIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentFeedbackIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.AssessmentMetaDataIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.EvaluationModelIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.ItemDataIfc; import org.sakaiproject.tool.assessment.data.ifc.assessment.SectionDataIfc; import org.sakaiproject.tool.assessment.data.ifc.questionpool.QuestionPoolItemIfc; import org.sakaiproject.tool.assessment.data.ifc.shared.TypeIfc; import org.sakaiproject.tool.assessment.data.model.Tree; import org.sakaiproject.tool.assessment.facade.AgentFacade; import org.sakaiproject.tool.assessment.facade.AssessmentFacade; import org.sakaiproject.tool.assessment.facade.ItemFacade; import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade; import org.sakaiproject.tool.assessment.facade.SectionFacade; import org.sakaiproject.tool.assessment.integration.helper.integrated.AgentHelperImpl; import org.sakaiproject.tool.assessment.qti.asi.Assessment; import org.sakaiproject.tool.assessment.qti.asi.Item; import org.sakaiproject.tool.assessment.qti.asi.Section; import org.sakaiproject.tool.assessment.qti.constants.QTIVersion; import org.sakaiproject.tool.assessment.qti.exception.RespondusMatchingException; import org.sakaiproject.tool.assessment.qti.helper.assessment.AssessmentHelperIfc; import org.sakaiproject.tool.assessment.qti.helper.item.ItemHelperIfc; import org.sakaiproject.tool.assessment.qti.helper.section.SectionHelperIfc; import org.sakaiproject.tool.assessment.qti.util.XmlStringBuffer; import org.sakaiproject.tool.assessment.qti.util.XmlUtil; import org.sakaiproject.tool.assessment.services.ItemService; import org.sakaiproject.tool.assessment.services.QuestionPoolService; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.tool.assessment.util.TextFormat; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.sakaiproject.util.FormattedText; /** * <p>Copyright: Copyright (c) 2004</p> * <p>Organization: Sakai Project</p> * @author Ed Smiley esmiley@stanford.edu * @author Shastri, Rashmi <rshastri@iupui.edu> * @version $Id$ */ public class AuthoringHelper { private static Log log = LogFactory.getLog(AuthoringHelper.class); // private static final AuthoringXml ax = new AuthoringXml(QTIVersion.VERSION_1_2); private AuthoringXml ax; private int qtiVersion; private static final String VALIDATE_XSD_PATH = "xml/xsd/"; private AuthoringHelper() { } /** * QTI versioned constructor * @param qtiVersion either QTIVersion.VERSION_1_2 or QTIVersion.VERSION_2_0; */ public AuthoringHelper(int qtiVersion) { this.qtiVersion = qtiVersion; if (!QTIVersion.isValid(qtiVersion)) { throw new IllegalArgumentException( "Version Codes supported: QTIVersion.VERSION_1_2, QTIVersion.VERSION_2_0"); } ax = new AuthoringXml(qtiVersion); } /** * Get a published assessment in Document form. * * @param assessmentId the published assessment's Id * @return the Document with the published assessment data */ public Document getAssessment(String assessmentId) { InputStream is = ax.getTemplateInputStream(ax.ASSESSMENT); return getAssessment(assessmentId, is); } /** * Get an assessment in Document form. * * @param assessmentId the assessment's Id * @param is a stream containing the unpopulated XML document * @return the Document with the published assessment data */ public Document getAssessment(String assessmentId, InputStream is) { try { String authors; String objectives; String keywords; String rubrics; String bgColor; String bgImage; AssessmentService assessmentService = new AssessmentService(); QTIHelperFactory factory = new QTIHelperFactory(); AssessmentFacade assessment = assessmentService.getAssessment(assessmentId); // convert assessment to document AssessmentHelperIfc assessmentHelper = factory.getAssessmentHelperInstance(this.qtiVersion); Assessment assessmentXml = assessmentHelper.readXMLDocument(is); assessmentXml.setIdent(assessmentId); assessmentXml.setTitle(FormattedText.convertFormattedTextToPlaintext(assessment.getTitle())); assessmentHelper.setDescriptiveText(assessment.getDescription(), assessmentXml); authors = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.AUTHORS); objectives = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.OBJECTIVES); keywords = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.KEYWORDS); rubrics = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.RUBRICS); bgColor = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.BGCOLOR); bgImage = assessment.getAssessmentMetaDataByLabel(AssessmentMetaDataIfc.BGIMAGE); if (authors != null) { assessmentXml.setFieldentry("AUTHORS", authors); } else { AgentHelperImpl helper = new AgentHelperImpl(); String createdBy = assessment.getCreatedBy(); String eid = helper.getEidById(createdBy); if (eid != null) { assessmentXml.setFieldentry("AUTHORS", eid); } else { log.debug("\n\nNO AUTHORS"); } } if (objectives != null) { assessmentXml.setFieldentry("ASSESSMENT_OBJECTIVES", objectives); } if (keywords != null) { assessmentXml.setFieldentry("ASSESSMENT_KEYWORDS", keywords); } if (rubrics != null) { assessmentXml.setFieldentry("ASSESSMENT_RUBRICS", rubrics); } if (bgColor != null) { assessmentXml.setFieldentry("BGCOLOR", bgColor); } if (bgImage != null) { assessmentXml.setFieldentry("BGIMG", bgImage); } // fieldentry properties EvaluationModelIfc evaluationModel = assessment.getEvaluationModel(); if (evaluationModel != null) { assessmentHelper.updateEvaluationModel(assessmentXml, evaluationModel); } AssessmentFeedbackIfc assessmentFeedback = assessment.getAssessmentFeedback(); if (assessmentFeedback != null) { assessmentHelper.updateFeedbackModel(assessmentXml, assessmentFeedback); } AssessmentAccessControlIfc assessmentAccessControl = assessment.getAssessmentAccessControl(); if (assessmentAccessControl != null) { assessmentHelper.updateAccessControl(assessmentXml, assessmentAccessControl); } // Respondus Locked Browser // To-do: To retain the value, need to re-organize SamigoApiFactory to samigo-api. /* if (assessment.getAssessmentMetaDataByLabel(SecureDeliveryServiceAPI.MODULE_KEY) == null || SecureDeliveryServiceAPI.NONE_ID.equals(assessment.getAssessmentMetaDataByLabel(SecureDeliveryServiceAPI.MODULE_KEY))) { assessmentXml.setFieldentry("REQUIRE_LOCKED_BROWSER", "True"); if (assessment.getAssessmentMetaDataByLabel( SecureDeliveryServiceAPI.EXITPWD_KEY ) != null) { SecureDeliveryServiceAPI secureDeliveryService = SamigoApiFactory.getInstance().getSecureDeliveryServiceAPI(); String exitPassword = secureDeliveryService.decryptPassword((String) assessment.getAssessmentMetaDataByLabel( SecureDeliveryServiceAPI.MODULE_KEY ), (String) assessment.getAssessmentMetaDataByLabel( SecureDeliveryServiceAPI.EXITPWD_KEY ) ); assessmentXml.setFieldentry("EXIT_PASSWARD", exitPassword); } } */ Set securedIPAddressSet = (Set) assessment.getSecuredIPAddressSet(); if (securedIPAddressSet != null) { assessmentHelper.updateIPAddressSet(assessmentXml, securedIPAddressSet); } Set attachmentSet = (Set) assessment.getAssessmentAttachmentSet(); if (attachmentSet != null && attachmentSet.size() != 0) { assessmentHelper.updateAttachmentSet(assessmentXml, attachmentSet); } assessmentHelper.updateMetaData(assessmentXml, assessment); // sections factory = new QTIHelperFactory(); SectionHelperIfc sectionHelper = factory.getSectionHelperInstance(this.qtiVersion); List sectionList = assessment.getSectionArraySorted(); for (int i = 0; i < sectionList.size(); i++) { SectionDataIfc section = (SectionDataIfc) sectionList.get(i); InputStream sis = ax.getTemplateInputStream(ax.SECTION); Section sectionXml = sectionHelper.readXMLDocument(sis); sectionXml.update(section); addSection(assessmentXml, sectionXml); } return assessmentXml.getDocument(); } catch (Exception e) { log.error(e.getMessage(), e); } return null; } /** * Get an object bank of items in Document form. * * @param itemIds array of the the item ids * @return the Document with the item bank data */ public Document getItemBank(String[] itemIds) { Document objectBank = XmlUtil.createDocument(); Element root = objectBank.createElement("questestinterop"); Element ob = objectBank.createElement("objectbank"); String objectBankIdent = "object" + Math.random(); ob.setAttribute("ident", objectBankIdent); for (int i = 0; i < itemIds.length; i++) { Document itemDoc = getItem(itemIds[i]); Element itemElement = itemDoc.getDocumentElement(); Node itemImport = objectBank.importNode(itemElement, true); ob.appendChild(itemImport); } root.appendChild(ob); objectBank.appendChild(root); return objectBank; } /** * Get an object bank of asessments (asi) in Document form. * * @param assessmentIds array of the the assessment ids * @return the Document with the item bank data */ public Document getAssessmentBank(String[] assessmentIds) { Document objectBank = XmlUtil.createDocument(); Element root = objectBank.createElement("questestinterop"); Element ob = objectBank.createElement("objectbank"); String objectBankIdent = "object" + Math.random(); ob.setAttribute("ident", objectBankIdent); for (int i = 0; i < assessmentIds.length; i++) { Document itemDoc = getAssessment(assessmentIds[i]); Element itemElement = itemDoc.getDocumentElement(); Node itemImport = objectBank.importNode(itemElement, true); ob.appendChild(itemImport); } root.appendChild(ob); objectBank.appendChild(root); return objectBank; } /** * Get an item in Document form. * @param itemId the item id * @return the Document with the item data */ public Document getItem(String itemId) { Item itemXml = new Item(this.qtiVersion); try { ItemService itemService = new ItemService(); QTIHelperFactory factory = new QTIHelperFactory(); ItemHelperIfc itemHelper = factory.getItemHelperInstance(this.qtiVersion); ItemDataIfc item = itemService.getItem(itemId); //TypeIfc type = item.getType(); Long type = item.getTypeId(); if ((TypeIfc.MULTIPLE_CHOICE_SURVEY).equals(type)) { String scale = item.getItemMetaDataByLabel(ItemMetaData.SCALENAME); itemXml = itemHelper.readTypeSurveyItem(scale); } else { itemXml = itemHelper.readTypeXMLItem(type); } itemXml.setIdent(item.getItemIdString()); itemXml.update(item); return itemXml.getDocument(); } catch (Exception ex) { log.error(ex); return null; } } /** * * @param assessmentXml * @param sectionXml * @throws IOException * @throws SAXException * @throws ParserConfigurationException */ private void addSection(Assessment assessmentXml, Section sectionXml) throws IOException, SAXException, ParserConfigurationException { ax.addElement(assessmentXml.getDocument(), "questestinterop/assessment", sectionXml.getDocument().getDocumentElement()); } /** * Get an InputStream to an unpopulated section XML from file system. * @return InputStream to an unpopulated section XML */ public InputStream getBlankSectionTemplateFileStream() { InputStream is = ax.getTemplateInputStream(ax.SECTION); return is; } /** * Pull apart object bank into multiple assessments * @param objectBank * @return an array of AssesmentFacades */ public AssessmentFacade[] createMultipleImportedAssessments(Document objectBank) { Document[] docs = getDocumentsFromObjectBankDoc(objectBank, "assessment"); return createMultipleImportedAssessments(docs); } /** * Pull apart object bank based on elementName * @param objectBank * @param elementName e.g. "assessment", "item", etc. * @return */ private Document[] getDocumentsFromObjectBankDoc(Document objectBank, String elementName) { Document[] documents = null; // Get the matching elements NodeList nodeList = objectBank.getElementsByTagName("//" + elementName); int numDocs = nodeList.getLength(); if (numDocs == 0) { return null; } documents = new Document[numDocs]; for (int i = 0; i < numDocs; i++) { Node node = (Node) nodeList.item(i); Document objectDoc = XmlUtil.createDocument(); Node importNode = objectDoc.importNode(node, true); objectDoc.appendChild(importNode); documents[i] = objectDoc; } return documents; } /** * Import multiple assessment documents in QTI format, extract & persist. * @param objectBank * @return an array of AssesmentFacades */ public AssessmentFacade[] createMultipleImportedAssessments(Document[] documents) { AssessmentFacade[] assessments = new AssessmentFacade[documents.length]; for (int i = 0; i < documents.length; i++) { assessments[i] = createImportedAssessment(documents[i]); } return assessments; } /** * Import an assessment XML document in QTI format, extract & persist the data. * @param document the assessment XML document in QTI format * @return a persisted assessment */ public AssessmentFacade createImportedAssessment(Document document) { return createImportedAssessment(document, null); } public AssessmentFacade createImportedAssessment(Document document, String unzipLocation) { return createImportedAssessment(document, unzipLocation, false, null); } public AssessmentFacade createImportedAssessment(Document document, String unzipLocation, boolean isRespondus, ArrayList failedMatchingQuestions) { return createImportedAssessment(document, unzipLocation, null, isRespondus, failedMatchingQuestions, null); } /** * Import an assessment XML document in QTI format, extract & persist the data. * @param document the assessment XML document in QTI format * @return a persisted assessment */ public AssessmentFacade createImportedAssessment(Document document, String unzipLocation, String templateId, String siteId) { return createImportedAssessment(document, unzipLocation, templateId, false, null, siteId); } private boolean validateImportXml(Document doc) throws SAXException, IOException { // 1. Lookup a factory for the W3C XML Schema language SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); // 2. Compile the schema. // Here the schema is loaded from a java.io.File, but you could use // a java.net.URL or a javax.xml.transform.Source instead. String schemaFile = VALIDATE_XSD_PATH + "qtiv1p2.xsd"; log.debug("schemaFile = " + schemaFile); Schema schema = factory.newSchema( new StreamSource(AuthoringHelper.class.getClassLoader().getResourceAsStream(schemaFile))); // 3. Get a validator from the schema. Validator validator = schema.newValidator(); // 4. Parse the document you want to check. Source source = new DOMSource(doc); // 5. Check the document try { validator.validate(source); log.debug("The xml is valid."); return true; } catch (SAXException ex) { log.debug("The xml is not valid QTI format.", ex); } return false; } protected String getAgentString() { return AgentFacade.getAgentString(); } public AssessmentFacade createImportedAssessment(Document document, String unzipLocation, String templateId, boolean isRespondus, ArrayList failedMatchingQuestions, String siteId) { AssessmentFacade assessment = null; AssessmentService assessmentService = new AssessmentService(); try { // we need to know who we are String me = getAgentString(); // create the assessment ExtractionHelper exHelper = new ExtractionHelper(this.qtiVersion); exHelper.setUnzipLocation(unzipLocation); ItemService itemService = new ItemService(); // we need to remove a default namespace if present Document removeNamespace = exHelper.getTransformDocument(exHelper.REMOVE_NAMESPACE_TRANSFORM); Document flatNamespaceXml = XmlUtil.transformDocument(document, removeNamespace); // validate xml // validate xml first boolean success = validateImportXml(flatNamespaceXml); if (!success) { throw (new RuntimeException("Invalid QTI XML format.")); } // else continue; Assessment assessmentXml = new Assessment(flatNamespaceXml); Map assessmentMap = exHelper.mapAssessment(assessmentXml, isRespondus); String description = (String) assessmentMap.get("description"); String title = TextFormat.convertPlaintextToFormattedTextNoHighUnicode(log, (String) assessmentMap.get("title")); assessment = assessmentService.createAssessmentWithoutDefaultSection(title, exHelper.makeFCKAttachment(description), null, templateId, siteId); // now make sure we have a unique name for the assessment String baseId = assessment.getAssessmentBaseId().toString(); boolean notUnique = !assessmentService.assessmentTitleIsUnique(baseId, title, false); if (notUnique) { synchronized (title) { log.debug("Assessment " + title + " is not unique."); int count = 0; // alternate exit condition while (notUnique) { title = exHelper.renameDuplicate(title); log.debug("renameDuplicate(title): " + title); assessment.setTitle(title); notUnique = !assessmentService.assessmentTitleIsUnique(baseId, title, false); if (count++ > 99) break;// exit condition in case bug is introduced } } } // update the remaining assessment properties if (isRespondus) { AssessmentAccessControl control = (AssessmentAccessControl) assessment.getAssessmentAccessControl(); if (control == null) { control = new AssessmentAccessControl(); control.setAssessmentBase(assessment.getData()); } EvaluationModel evaluationModel = (EvaluationModel) assessment.getEvaluationModel(); if (evaluationModel == null) { evaluationModel = new EvaluationModel(); evaluationModel.setAssessmentBase(assessment.getData()); } AssessmentFeedback feedback = (AssessmentFeedback) assessment.getAssessmentFeedback(); if (feedback == null) { feedback = new AssessmentFeedback(); feedback.setAssessmentBase(assessment.getData()); } } else { exHelper.updateAssessment(assessment, assessmentMap); } // make sure required fields are set assessment.setCreatedBy(me); assessment.setCreatedDate(assessment.getCreatedDate()); assessment.setLastModifiedBy(me); assessment.setLastModifiedDate(assessment.getCreatedDate()); assessment.setTypeId(TypeIfc.QUIZ); assessment.setStatus(Integer.valueOf(1)); // set comments String comments = (String) assessmentMap.get("comments"); assessment.setComments(comments); // process each section and each item within each section List sectionList = exHelper.getSectionXmlList(assessmentXml); int sectionListSize = sectionList.size(); log.debug("sections=" + sectionListSize); for (int sec = 0; sec < sectionListSize; sec++) // for each section... { Section sectionXml = (Section) sectionList.get(sec); Map sectionMap = exHelper.mapSection(sectionXml, isRespondus); // create the assessment section SectionFacade section = assessmentService.addSection("" + assessment.getAssessmentId()); exHelper.updateSection(section, sectionMap); // make sure we are the creator section.setCreatedBy(me); section.setCreatedDate(assessment.getCreatedDate()); section.setLastModifiedBy(me); section.setLastModifiedDate(assessment.getCreatedDate()); section.setTypeId(TypeIfc.DEFAULT_SECTION); section.setStatus(Integer.valueOf(1)); section.setSequence(Integer.valueOf(sec + 1)); List itemList = exHelper.getItemXmlList(sectionXml); for (int itm = 0; itm < itemList.size(); itm++) // for each item { log.debug("items=" + itemList.size()); Item itemXml = (Item) itemList.get(itm); ItemFacade item = new ItemFacade(); try { exHelper.updateItem(item, itemXml, isRespondus); } catch (RespondusMatchingException rme) { if (failedMatchingQuestions != null) { failedMatchingQuestions.add(itm + 1); } } // make sure required fields are set item.setCreatedBy(me); item.setCreatedDate(assessment.getCreatedDate()); item.setLastModifiedBy(me); item.setLastModifiedDate(assessment.getCreatedDate()); item.setStatus(ItemDataIfc.ACTIVE_STATUS); // assign the next sequence number item.setSequence(Integer.valueOf(itm + 1)); // add item to section item.setSection(section); // one to many // update metadata with PARTID item.addItemMetaData(ItemMetaData.PARTID, section.getSectionId().toString()); // Item Attachment exHelper.makeItemAttachmentSet(item); section.addItem(item); // many to one itemService.saveItem(item); } // ... end for each item // Section Attachment exHelper.makeSectionAttachmentSet(section, sectionMap); assessmentService.saveOrUpdateSection(section); } // ... end for each section // and add ip address restriction, if any String allowIp = assessment.getAssessmentMetaDataByLabel("ALLOW_IP"); //log.info("allowIp: " + allowIp); if (allowIp != null && !allowIp.trim().equalsIgnoreCase("null")) { //log.info("NOT NULL: " + allowIp); exHelper.makeSecuredIPAddressSet(assessment, allowIp); //Clean unnecesary ip metadata that fail when an assessment //with more than 256 charts in the field ALLOWED IPS is imported Set assessmentSet = assessment.getAssessmentMetaDataSet(); Iterator assessmentSetIterator = assessmentSet.iterator(); while (assessmentSetIterator.hasNext()) { AssessmentMetaData assessmentMetaData = (AssessmentMetaData) assessmentSetIterator.next(); if ("ALLOW_IP".equals(assessmentMetaData.getLabel())) { assessmentSetIterator.remove(); break; } } } // Assessment Attachment exHelper.makeAssessmentAttachmentSet(assessment); String siteTitle = SiteService.getSite(ToolManager.getCurrentPlacement().getContext()).getTitle(); if (siteTitle != null && !siteTitle.equals(assessment.getAssessmentAccessControl().getReleaseTo())) { assessment.getAssessmentAccessControl().setReleaseTo(siteTitle); } assessmentService.saveAssessment(assessment); return assessment; } catch (RespondusMatchingException rme) { log.error(rme.getMessage(), rme); assessmentService.removeAssessment(assessment.getAssessmentId().toString()); throw new RespondusMatchingException(rme); } catch (Exception e) { log.error(e.getMessage(), e); assessmentService.removeAssessment(assessment.getAssessmentId().toString()); throw new RuntimeException(e); } } /** * Import an assessment XML document in QTI format, extract & persist the data. * import process assumes assessment structure, not objectbank or itembank * @param document the assessment XML document in QTI format * @return a persisted assessment */ public QuestionPoolFacade createImportedQuestionPool(Document document) { QuestionPoolFacade questionpool = new QuestionPoolFacade(); QuestionPoolService questionPoolService = new QuestionPoolService(); try { // identify user to assign as question pool owner String me = AgentFacade.getAgentString(); // create the questionpool as an assessment ExtractionHelper exHelper = new ExtractionHelper(this.qtiVersion); ItemService itemService = new ItemService(); // we need to remove a default namespace if present Document removeNamespace = exHelper.getTransformDocument(exHelper.REMOVE_NAMESPACE_TRANSFORM); Document flatNamespaceXml = XmlUtil.transformDocument(document, removeNamespace); Assessment assessmentXml = new Assessment(flatNamespaceXml); // validate xml first boolean success = validateImportXml(flatNamespaceXml); if (!success) { throw (new RuntimeException("Invalid QTI XML format.")); } // else continue; Map assessmentMap = exHelper.mapAssessment(assessmentXml); String title = (String) assessmentMap.get("title"); // save questionpool with required info only at this point questionpool.setOwnerId(me); questionpool.setTitle(title); questionpool.setLastModifiedById(me); questionpool.setAccessTypeId(QuestionPoolFacade.ACCESS_DENIED); // set as default questionpool = questionPoolService.savePool(questionpool); // update the remaining questionpool properties exHelper.updateQuestionPool(questionpool, assessmentMap); // now make sure we have a unique name for the question pool String baseId = questionpool.getQuestionPoolId().toString(); boolean isUnique = questionPoolService.poolIsUnique(baseId, title, "0", me); // if the title is not unique, increment with a number per renameDuplicate() if (!isUnique) { synchronized (title) { log.debug("Questionpool " + title + " is not unique."); int count = 0; // alternate exit condition while (!isUnique) { title = exHelper.renameDuplicate(title); log.debug("renameDuplicate(title): " + title); questionpool.setTitle(title); //recheck to confirm that new title is not a dplicate too isUnique = questionPoolService.poolIsUnique(baseId, title, "0", me); if (count++ > 99) break;// exit condition in case bug is introduced } } } // process each section and each item within assessment each section List sectionList = exHelper.getSectionXmlList(assessmentXml); int sectionListSize = sectionList.size(); log.debug("sections=" + sectionListSize); // initialize setQuestionPoolItems so items can be added Set itemSet = new HashSet(); questionpool.setQuestionPoolItems(itemSet); for (int sec = 0; sec < sectionListSize; sec++) { Section sectionXml = (Section) sectionList.get(sec); Map sectionMap = exHelper.mapSection(sectionXml); // for single section, do not create subpool List itemList = exHelper.getItemXmlList(sectionXml); for (int itm = 0; itm < itemList.size(); itm++) // for each item { log.debug("items=" + itemList.size()); Item itemXml = (Item) itemList.get(itm); ItemFacade item = new ItemFacade(); exHelper.updateItem(item, itemXml); // make sure required fields are set item.setCreatedBy(me); item.setCreatedDate(questionpool.getLastModified()); item.setLastModifiedBy(me); item.setLastModifiedDate(questionpool.getLastModified()); item.setStatus(ItemDataIfc.ACTIVE_STATUS); itemService.saveItem(item); QuestionPoolItemData questionPoolItem = new QuestionPoolItemData(); questionPoolItem.setQuestionPoolId(questionpool.getQuestionPoolId()); questionPoolItem.setItemId(item.getItemId()); questionpool.addQuestionPoolItem((QuestionPoolItemIfc) questionPoolItem); } // ... end for each item } // need error message if more than one section, for now // update the questionpoool with all sections and items questionPoolService.savePool(questionpool); return questionpool; } catch (Exception e) { log.error(e.getMessage(), e); questionPoolService.deletePool(questionpool.getQuestionPoolId(), AgentFacade.getAgentString(), null); throw new RuntimeException(e); } } /** * @deprecated * Import an item XML document in QTI format, extract & persist the data. * @param document the item XML document in QTI format * @return a persisted item */ public ItemFacade createImportedItem(Document document) { ItemFacade item = new ItemFacade(); try { // create the item ExtractionHelper exHelper = new ExtractionHelper(this.qtiVersion); Item itemXml = new Item(document, QTIVersion.VERSION_1_2); exHelper.updateItem(item, itemXml); ItemService itemService = new ItemService(); itemService.saveItem(item); } catch (Exception e) { log.error(e.getMessage(), e); } return item; } /** * Create an XmlStringBuffer (base class for A,S,I XML classes) * * @param inputStream the input stram * * @return an XmlStringBuffer (this is the base class for A,S,I XML classes) */ public XmlStringBuffer readXMLDocument(InputStream inputStream) { Document document = null; DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); // builderFactory.setNamespaceAware(true); try { DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder(); document = documentBuilder.parse(inputStream); } catch (ParserConfigurationException e) { log.error(e.getMessage(), e); } catch (SAXException e) { log.error(e.getMessage(), e); } catch (IOException e) { log.error(e.getMessage(), e); } return new XmlStringBuffer(document); } /** * Helper method. * @param inputStr * @param delimiter * @return */ public ArrayList changeDelimitedStringtoArray(String inputStr, String delimiter) { ArrayList selectedList = new ArrayList(); if (inputStr != null && inputStr.trim().length() > 0) { StringTokenizer st = new StringTokenizer(inputStr, delimiter); if (st != null) { while (st.hasMoreTokens()) { selectedList.add(st.nextToken()); } } else { selectedList.add(inputStr); } } return selectedList; } public int getQtiVersion() { return qtiVersion; } public void setQtiVersion(int qtiVersion) { this.qtiVersion = qtiVersion; } }