/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-cp/src/java/org/sakaiproject/tool/assessment/contentpackaging/ManifestGenerator.java $ * $Id: ManifestGenerator.java 110693 2012-07-24 23:27:54Z ktsao@stanford.edu $ *********************************************************************************** * * Copyright (c) 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.contentpackaging; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; import org.w3c.dom.Text; import org.w3c.dom.Element; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.exception.ServerOverloadException; import org.sakaiproject.exception.TypeException; 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.AssessmentAttachment; import org.sakaiproject.tool.assessment.data.dao.assessment.AssessmentData; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemAttachment; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemData; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemFeedback; import org.sakaiproject.tool.assessment.data.dao.assessment.ItemText; import org.sakaiproject.tool.assessment.data.dao.assessment.SectionAttachment; import org.sakaiproject.tool.assessment.data.dao.assessment.SectionData; import org.sakaiproject.tool.assessment.data.ifc.shared.TypeIfc; import org.sakaiproject.tool.assessment.facade.AssessmentFacade; import org.sakaiproject.tool.assessment.facade.SectionFacade; import org.sakaiproject.tool.assessment.qti.util.XmlUtil; import org.sakaiproject.tool.assessment.services.assessment.AssessmentService; import org.sakaiproject.user.api.User; import org.sakaiproject.user.cover.UserDirectoryService; import org.xml.sax.SAXException; import org.sakaiproject.content.api.ContentHostingService; /** * <p> * Copyright: Copyright (c) 2007 Sakai * </p> * * @version $Id: ManifestGenerator.java 110693 2012-07-24 23:27:54Z ktsao@stanford.edu $ */ public class ManifestGenerator { private static Log log = LogFactory.getLog(ManifestGenerator.class); /**default namespace and metadata namespace*/ private static String DEFAULT_NAMESPACE_URI = "http://www.imsglobal.org/xsd/imscp_v1p1"; private static String DEFAULT_NAMESPACE_SCHEMA_LOCATION = "http://www.imsglobal.org/xsd/imscp_v1p1.xsd"; private static String IMSMD_NAMESPACE_URI = "http://www.imsglobal.org/xsd/imsmd_v1p2"; private static String IMSMD_NAMESPACE_SCHEMA_LOCATION = "http://www.imsglobal.org/xsd/imsmd_v1p2.xsd"; private static String EXPORT_ASSESSMENT = "exportAssessment"; private static String EXPORT_ASSESSMENT_XML = EXPORT_ASSESSMENT + ".xml"; private Document document; private String assessmentId; private HashMap contentMap = new HashMap(); private ContentHostingService contentHostingService; public ManifestGenerator(String assessmentId) { this.assessmentId = assessmentId; } public String getManifest() { document = readXMLDocument(); if (document == null) { log.info("document == null"); return ""; } String xmlString = XmlUtil.getDOMString(document); String newXmlString = xmlString; if (xmlString.startsWith("<?xml version")) { newXmlString = xmlString.replaceFirst("version=\"1.0\"", "version=\"1.0\" encoding=\"UTF-8\""); } log.debug(newXmlString); return newXmlString; } public HashMap getContentMap() { return contentMap; } private Document readXMLDocument() { document = getDocument(); // Need to create upper level metadata elements Element manifestElement = createManifestElement(); document.appendChild(manifestElement); // create manifest metadata Element metadata = createDefaultNSElement("metadata"); appendLOMMetadataToElement(EXPORT_ASSESSMENT, metadata); manifestElement.appendChild(metadata); // Need organizations element Element organizationsElement = createOrganizationsElement(); manifestElement.appendChild(organizationsElement); // resources Element resourcesElement = createDefaultNSElement("resources"); // resource Element resourceElement = createResourceElement(); Element xmlFileElement = createFileElement(EXPORT_ASSESSMENT_XML); resourceElement.appendChild(xmlFileElement); setContentHostingService(); getAttachments(); getFCKAttachments(); Iterator iter = contentMap.keySet().iterator(); String filename = null; Element fileElement = null; while (iter.hasNext()) { filename = ((String) iter.next()).replaceAll(" ", ""); fileElement = createFileElement(filename); resourceElement.appendChild(fileElement); } resourcesElement.appendChild(resourceElement); manifestElement.appendChild(resourcesElement); return document; } private void getAttachments() { try { AssessmentService assessmentService = new AssessmentService(); AssessmentFacade assessment = assessmentService .getAssessment(assessmentId); // Assessment attachment AssessmentData assessmentData = (AssessmentData) assessment .getData(); Set assessmentAttachmentSet = assessmentData .getAssessmentAttachmentSet(); Iterator assessmentAttachmentIter = assessmentAttachmentSet .iterator(); byte[] content = null; String resourceId = null; // resoureId is also the filename (whole // path) in the zip file while (assessmentAttachmentIter.hasNext()) { AssessmentAttachment assessmentAttachment = (AssessmentAttachment) assessmentAttachmentIter .next(); resourceId = assessmentAttachment.getResourceId(); content = contentHostingService.getResource(resourceId) .getContent(); contentMap.put(resourceId.replace(" ", ""), content); } // Section attachment Set sectionSet = assessment.getSectionSet(); Iterator sectionIter = sectionSet.iterator(); SectionData sectionData = null; Set sectionAttachmentSet = null; Iterator sectionAttachmentIter = null; SectionAttachment sectionAttachment = null; Set itemSet = null; ItemData itemData = null; Set itemAttachmentSet = null; Iterator itemAttachmentIter = null; ItemAttachment itemAttachment = null; while (sectionIter.hasNext()) { sectionData = (SectionData) ((SectionFacade) sectionIter.next()) .getData(); sectionAttachmentSet = sectionData.getSectionAttachmentSet(); sectionAttachmentIter = sectionAttachmentSet.iterator(); while (sectionAttachmentIter.hasNext()) { sectionAttachment = (SectionAttachment) sectionAttachmentIter .next(); resourceId = sectionAttachment.getResourceId(); content = contentHostingService.getResource(resourceId) .getContent(); contentMap.put(resourceId.replace(" ", ""), content); } itemSet = sectionData.getItemSet(); Iterator itemIter = itemSet.iterator(); while (itemIter.hasNext()) { itemData = (ItemData) itemIter.next(); itemAttachmentSet = itemData.getItemAttachmentSet(); itemAttachmentIter = itemAttachmentSet.iterator(); while (itemAttachmentIter.hasNext()) { itemAttachment = (ItemAttachment) itemAttachmentIter .next(); resourceId = itemAttachment.getResourceId(); content = contentHostingService.getResource(resourceId) .getContent(); contentMap.put(resourceId.replace(" ", ""), content); } } } } catch (PermissionException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (IdUnusedException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (TypeException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (ServerOverloadException e) { log.error(e.getMessage()); e.printStackTrace(); } } private void getFCKAttachments() { AssessmentService assessmentService = new AssessmentService(); AssessmentFacade assessment = assessmentService .getAssessment(assessmentId); // Assessment FCK attachment AssessmentData assessmentData = (AssessmentData) assessment.getData(); processDescription(assessmentData.getDescription()); processDescription(assessmentData.getAssessmentAccessControl().getSubmissionMessage()); // Section FCK attachment Set sectionSet = assessment.getSectionSet(); Iterator sectionIter = sectionSet.iterator(); SectionData sectionData = null; Set itemSet = null; ItemData itemData = null; while (sectionIter.hasNext()) { sectionData = (SectionData) ((SectionFacade) sectionIter.next()) .getData(); processDescription(sectionData.getDescription()); itemSet = sectionData.getItemSet(); Iterator itemIter = itemSet.iterator(); while (itemIter.hasNext()) { itemData = (ItemData) itemIter.next(); // Question Text if (itemData.getTypeId().equals(TypeIfc.MATCHING)) { processDescription(itemData.getInstruction()); } Set itemTextSet = itemData.getItemTextSet(); ItemText itemText = null; Iterator itemTextIter = itemTextSet.iterator(); while (itemTextIter.hasNext()) { itemText = (ItemText) itemTextIter.next(); processDescription(itemText.getText()); // Answer Set answerSet = itemText.getAnswerSet(); Answer answer = null; Iterator answerIter = answerSet.iterator(); while (answerIter.hasNext()) { answer = (Answer) answerIter.next(); processDescription(answer.getText()); // Answer Feedback Set answerFeedbackSet = answer.getAnswerFeedbackSet(); AnswerFeedback answerFeedback = null; Iterator answerFeedbackIter = answerFeedbackSet.iterator(); while (answerFeedbackIter.hasNext()) { answerFeedback = (AnswerFeedback) answerFeedbackIter.next(); processDescription(answerFeedback.getText()); } } } // Feedback Set itemFeedbackSet = itemData.getItemFeedbackSet(); ItemFeedback itemFeedback = null; Iterator itemFeedbackIter = itemFeedbackSet.iterator(); while (itemFeedbackIter.hasNext()) { itemFeedback = (ItemFeedback) itemFeedbackIter.next(); processDescription(itemFeedback.getText()); } } } } private void processDescription(String description) { String prependString = ServerConfigurationService.getAccessUrl() + contentHostingService.REFERENCE_ROOT; // Hardcode here for now because I cannot find the API to get them // Also, it is hardcoded in BaseContentService.java String siteCollection = "/group/"; String userCollection = "/user/"; String attachment = "/attachment/"; User user = UserDirectoryService.getCurrentUser(); String userId = user.getId(); String eid = user.getEid(); try { if (description != null && description.indexOf("<img ") > -1) { byte[] content = null; int srcStartIndex = 0; int srcEndIndex = 0; String src = null; String resourceId = null; String eidResourceId = null; String[] splittedString = description.split("<img "); for (int i = 0; i < splittedString.length; i++) { log.debug("splittedString[" + i + "] = " + splittedString[i]); if (splittedString[i].indexOf(prependString) > -1) { srcStartIndex = splittedString[i].indexOf("src=\""); srcEndIndex = splittedString[i].indexOf("\"", srcStartIndex + 5); src = splittedString[i].substring(srcStartIndex + 5, srcEndIndex); try { src = URLDecoder.decode(src, "UTF-8"); } catch (UnsupportedEncodingException e) { log.error(e.getMessage()); e.printStackTrace(); } if (src.indexOf(siteCollection) > -1) { resourceId = src.replace(prependString, ""); content = contentHostingService.getResource(resourceId).getContent(); if (content != null) { contentMap.put(resourceId.replace(" ", ""), content); } } else if (src.indexOf(userCollection) > -1) { eidResourceId = src.replace(prependString, ""); resourceId = eidResourceId.replace(eid, userId); content = contentHostingService.getResource(resourceId).getContent(); if (content != null) { contentMap.put(eidResourceId.replace(" ", ""), content); } } else if (src.indexOf(attachment) > -1) { resourceId = src.replace(prependString, ""); content = contentHostingService.getResource(resourceId).getContent(); if (content != null) { contentMap.put(resourceId.replace(" ", ""), content); } } else { log.error("Neither group nor user"); } } } } } catch (PermissionException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (IdUnusedException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (TypeException e) { log.error(e.getMessage()); e.printStackTrace(); } catch (ServerOverloadException e) { log.error(e.getMessage()); e.printStackTrace(); } } public void setContentHostingService(){ if (contentHostingService == null) { this.contentHostingService = AssessmentService.getContentHostingService(); } } private Element createManifestElement() { Element manifest = createDefaultNSElement("manifest"); manifest.setAttribute("identifier", "MANIFEST1"); manifest.setAttribute("xmlns", DEFAULT_NAMESPACE_URI); manifest.setAttribute("xmlns:imsmd", IMSMD_NAMESPACE_URI); manifest.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); manifest.setAttribute("xsi:schemaLocation", DEFAULT_NAMESPACE_URI + " " + DEFAULT_NAMESPACE_SCHEMA_LOCATION + " " + IMSMD_NAMESPACE_URI + " " + IMSMD_NAMESPACE_SCHEMA_LOCATION); return manifest; } public void appendLOMMetadataToElement(String title, Element parent) { // imsmd:lom Element imsmdLom = createLOMElement("lom"); // imsmd:general Element imsmdGeneral = createLOMElement("general"); // imsmd:identifier String identifier = Long.toHexString((new Date()).getTime()); Element imsmdIdentifier = createLOMElementWithLangstring("identifier", identifier); imsmdGeneral.appendChild(imsmdIdentifier); // imsmd:title Element imsmdTitle = createLOMElementWithLangstring("title", title); imsmdGeneral.appendChild(imsmdTitle); imsmdLom.appendChild(imsmdGeneral); parent.appendChild(imsmdLom); } private Element createOrganizationsElement() { Element organizations = createDefaultNSElement("organizations"); return organizations; } public Element createResourceElement() { Element resourceElement = createDefaultNSElement("resource"); resourceElement.setAttributeNS(DEFAULT_NAMESPACE_URI, "identifier", "RESOURCE1"); resourceElement.setAttributeNS(DEFAULT_NAMESPACE_URI, "type","imsqti_xmlv1p1"); resourceElement.setAttributeNS(DEFAULT_NAMESPACE_URI, "href", EXPORT_ASSESSMENT_XML); return resourceElement; } public Element createFileElement(String href) { Element fileElement = createDefaultNSElement("file"); fileElement.setAttributeNS(DEFAULT_NAMESPACE_URI, "href", href); return fileElement; } private Element createDefaultNSElement(String elename) { return getDocument().createElementNS(DEFAULT_NAMESPACE_URI, elename); } private Element createLOMElement(String elename) { Element imsmdlom = getDocument().createElementNS(IMSMD_NAMESPACE_URI, elename); imsmdlom.setPrefix("imsmd"); return imsmdlom; } private Element createLOMElementWithLangstring(String elementName, String text) { Element element = createLOMElement(elementName); //imsmd:langstring Element imsmdlangstring = createLOMElement("langstring"); imsmdlangstring.setAttribute("xml:lang", "en-US"); setNodeValue(imsmdlangstring, text); element.appendChild(imsmdlangstring); return element; } private void setNodeValue( Element parent, String data ) { Text textNode = getDocument().createTextNode(data); parent.appendChild( textNode ); } private Document getDocument() { if (document != null) return document; else document = XmlUtil.createDocument(); return document; } }