/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/common/trunk/import-parsers/common-cartridge/src/java/org/sakaiproject/importer/impl/CommonCartridgeFileParser.java $ * $Id: CommonCartridgeFileParser.java 118267 2013-01-10 22:29:52Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 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.importer.impl; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.archive.api.ImportMetadata; import org.sakaiproject.importer.api.ImportFileParser; import org.sakaiproject.importer.api.Importable; import org.sakaiproject.importer.impl.importables.Folder; import org.sakaiproject.importer.impl.translators.CCAssessmentTranslator; import org.sakaiproject.importer.impl.translators.CCDiscussionTopicTranslator; import org.sakaiproject.importer.impl.translators.CCLearningApplicationResourceTranslator; import org.sakaiproject.importer.impl.translators.CCWebContentTranslator; import org.sakaiproject.importer.impl.translators.CCWebLinkTranslator; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.SAXException; public class CommonCartridgeFileParser extends IMSFileParser { private static final String CC_NAMESPACE_URI = "http://www.imsglobal.org/xsd/imscc/imscp_v1p1"; /** Our logger. */ private static Log M_log = LogFactory.getLog(CommonCartridgeFileParser.class); public CommonCartridgeFileParser() { // add resource translators here addResourceTranslator(new CCAssessmentTranslator()); addResourceTranslator(new CCWebLinkTranslator()); addResourceTranslator(new CCWebContentTranslator()); addResourceTranslator(new CCDiscussionTopicTranslator()); addResourceTranslator(new CCLearningApplicationResourceTranslator()); resourceHelper = new CCResourceHelper(); itemHelper = new CCItemHelper(); fileHelper = new CCFileHelper(); manifestHelper = new CCManifestHelper(); } public boolean isValidArchive(InputStream fileData) { if (super.isValidArchive(fileData)) { Document manifest = extractFileAsDOM("/imsmanifest.xml", fileData); return (enclosingDocumentContainsNamespaceDeclaration(manifest, CC_NAMESPACE_URI)); } else return false; } private boolean enclosingDocumentContainsNamespaceDeclaration(Node node, String nameSpaceURI) { return node.isDefaultNamespace(CC_NAMESPACE_URI); } public ImportFileParser newParser() { return new CommonCartridgeFileParser(); } protected Collection getCategoriesFromArchive(String pathToData) { Collection categories = new ArrayList(); ImportMetadata im; // if(XPathHelper.getNodeValue("//resource[@type='webcontent']", this.archiveManifest) != null) { // im = new BasicImportMetadata(); // im.setId("webcontent"); // im.setLegacyTool("Web Content"); // im.setMandatory(false); // im.setFileName(".xml"); // im.setSakaiServiceName("ContentHostingService"); // im.setSakaiTool("Resources"); // categories.add(im); // } // if(XPathHelper.getNodeValue("//resource[@type='imsqti_xmlv1p2/imscc_xmlv1p0/assessment']", this.archiveManifest) != null) { // im = new BasicImportMetadata(); // im.setId("assessments"); // im.setLegacyTool("Assessments"); // im.setMandatory(false); // im.setFileName(".xml"); // im.setSakaiServiceName("Samigo"); // im.setSakaiTool("Tests and Quizzes"); // categories.add(im); // } Node topLevelItem; List topLevelItems = manifestHelper.getTopLevelItemNodes(this.archiveManifest); for(Iterator i = topLevelItems.iterator(); i.hasNext(); ) { topLevelItem = (Node)i.next(); im = new BasicImportMetadata(); im.setId(itemHelper.getId(topLevelItem)); im.setLegacyTool(itemHelper.getTitle(topLevelItem)); im.setMandatory(false); im.setFileName(".xml"); im.setSakaiServiceName("ContentHostingService"); im.setSakaiTool("Resources"); categories.add(im); } return categories; } protected boolean isCompoundDocument(Node node, Document resourceDescriptor) { // TODO Auto-generated method stub return false; } protected class CCResourceHelper extends ResourceHelper { public String getTitle(Node resourceNode) { String title = null; Node itemNode = XPathHelper.selectNode("//item[@identifierref='" + this.getId(resourceNode) + "']", resourceNode.getOwnerDocument()); if (itemNode != null) { title = XPathHelper.getNodeValue("./title", itemNode); if (title == null || "".equals(title)) { Document descriptor = getDescriptor(resourceNode); if (descriptor != null) { title = XPathHelper.getNodeValue("/CONTENT/TITLE",descriptor); } } } return title; } public String getType(Node resourceNode) { return XPathHelper.getNodeValue("./@type", resourceNode); } public String getId(Node resourceNode) { return XPathHelper.getNodeValue("./@identifier", resourceNode); } public Document getDescriptor(Node resourceNode) { String descriptorFilename = XPathHelper.getNodeValue("./file/@href",resourceNode).replaceAll("[/\\\\]+", "\\" + File.separator); Document doc = null; DocumentBuilder docBuilder; InputStream fis = null; // There is no reason to attempt to parse the file for a title unless it can be parsed String lowerFilename = descriptorFilename.toLowerCase(); if (!lowerFilename.endsWith(".xml") && !lowerFilename.endsWith(".html") && !lowerFilename.endsWith(".htm") && !lowerFilename.endsWith(".xhtml")) { return doc; } try { fis = new FileInputStream(pathToData + File.separator + descriptorFilename); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); docBuilder = builderFactory.newDocumentBuilder(); doc = (Document) docBuilder.parse(fis); } catch (FileNotFoundException e) { M_log.warn("getDescriptor() file not found: " + pathToData + File.separator + descriptorFilename); } catch (ParserConfigurationException e) { M_log.warn("getDescriptor() parser config error: " + e.getMessage()); } catch (SAXException e) { M_log.warn("getDescriptor() SAX parse error on file " + pathToData + File.separator + descriptorFilename + ": " + e.getMessage()); } catch (IOException e) { M_log.warn("getDescriptor() file IO exception", e); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // oh well, we tried } } } return doc; } public String getDescription(Node resourceNode) { Document descriptor = resourceHelper.getDescriptor(resourceNode); String desc = XPathHelper.getNodeValue("//TEXT", descriptor); return desc; } public boolean isFolder(Document resourceDescriptor) { return "true".equals(XPathHelper.getNodeValue("/CONTENT/FLAGS/ISFOLDER/@value", resourceDescriptor)); } } protected class CCItemHelper extends ItemHelper { public String getId(Node itemNode) { return XPathHelper.getNodeValue("./@identifier", itemNode); } public String getTitle(Node itemNode) { return XPathHelper.getNodeValue("./title",itemNode); } public String getDescription(Node itemNode) { String resourceId = XPathHelper.getNodeValue("./@identifierref", itemNode); Node resourceNode = manifestHelper.getResourceForId(resourceId, archiveManifest); return resourceHelper.getDescription(resourceNode); } } protected class CCManifestHelper extends ManifestHelper { public List getItemNodes(Document manifest) { return XPathHelper.selectNodes("//item", manifest); } public Node getResourceForId(String resourceId, Document manifest) { return XPathHelper.selectNode("//resource[@identifier='" + resourceId + "']",archiveManifest); } public List getResourceNodes(Document manifest) { return XPathHelper.selectNodes("//resource", manifest); } public List getTopLevelItemNodes(Document manifest) { List items = XPathHelper.selectNodes("//organization/item", manifest); if (items != null && items.size() > 1) return items; items = XPathHelper.selectNodes("//organization/item/item", manifest); if (items != null && items.size() > 1) return items; return XPathHelper.selectNodes("//organization/item/item/item", manifest); } } protected class CCFileHelper extends FileHelper { public String getFilePathForNode(Node node, String basePath) { return XPathHelper.getNodeValue("./@href", node); } } @Override protected Importable getCompanionForCompoundDocument(Document resourceDescriptor, Folder folder) { // TODO Auto-generated method stub return null; } @Override protected boolean wantsCompanionForCompoundDocument() { // TODO Auto-generated method stub return false; } }