Java tutorial
/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.ims.qti.qpool; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.IOUtils; import org.cyberneko.html.parsers.SAXParser; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentFactory; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.FileUtils; import org.olat.core.util.PathUtils.CopyVisitor; import org.olat.core.util.PathUtils.YesMatcher; import org.olat.core.util.StringHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.vfs.LocalImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSLeaf; import org.olat.core.util.xml.XMLParser; import org.olat.ims.qti.QTIConstants; import org.olat.ims.qti.editor.beecom.objects.QTIDocument; import org.olat.ims.qti.editor.beecom.objects.Question; import org.olat.ims.qti.editor.beecom.parser.ItemParser; import org.olat.ims.qti.questionimport.ItemAndMetadata; import org.olat.ims.resources.IMSEntityResolver; import org.olat.modules.qpool.QuestionItem; import org.olat.modules.qpool.QuestionType; import org.olat.modules.qpool.TaxonomyLevel; import org.olat.modules.qpool.manager.QEducationalContextDAO; import org.olat.modules.qpool.manager.QItemTypeDAO; import org.olat.modules.qpool.manager.QLicenseDAO; import org.olat.modules.qpool.manager.QPoolFileStorage; import org.olat.modules.qpool.manager.QuestionItemDAO; import org.olat.modules.qpool.manager.TaxonomyLevelDAO; import org.olat.modules.qpool.model.QEducationalContext; import org.olat.modules.qpool.model.QItemType; import org.olat.modules.qpool.model.QLicense; import org.olat.modules.qpool.model.QuestionItemImpl; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * This class is NOT thread-safe * * Initial date: 07.03.2013<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ class QTIImportProcessor { private static final OLog log = Tracing.createLoggerFor(QTIImportProcessor.class); private static final String OPENOLAT_MOVIE_MARKER = "BPlayer.insertPlayer("; private final Identity owner; private final Locale defaultLocale; private final String importedFilename; private final File importedFile; private final DB dbInstance; private final QLicenseDAO qLicenseDao; private final QItemTypeDAO qItemTypeDao; private final QPoolFileStorage qpoolFileStorage; private final QuestionItemDAO questionItemDao; private final TaxonomyLevelDAO taxonomyLevelDao; private final QEducationalContextDAO qEduContextDao; public QTIImportProcessor(Identity owner, Locale defaultLocale, QuestionItemDAO questionItemDao, QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao, TaxonomyLevelDAO taxonomyLevelDao, QLicenseDAO qLicenseDao, QPoolFileStorage qpoolFileStorage, DB dbInstance) { this(owner, defaultLocale, null, null, questionItemDao, qItemTypeDao, qEduContextDao, taxonomyLevelDao, qLicenseDao, qpoolFileStorage, dbInstance); } public QTIImportProcessor(Identity owner, Locale defaultLocale, String importedFilename, File importedFile, QuestionItemDAO questionItemDao, QItemTypeDAO qItemTypeDao, QEducationalContextDAO qEduContextDao, TaxonomyLevelDAO taxonomyLevelDao, QLicenseDAO qLicenseDao, QPoolFileStorage qpoolFileStorage, DB dbInstance) { this.owner = owner; this.dbInstance = dbInstance; this.defaultLocale = defaultLocale; this.importedFilename = importedFilename; this.importedFile = importedFile; this.qLicenseDao = qLicenseDao; this.qItemTypeDao = qItemTypeDao; this.questionItemDao = questionItemDao; this.qEduContextDao = qEduContextDao; this.qpoolFileStorage = qpoolFileStorage; this.taxonomyLevelDao = taxonomyLevelDao; } public List<QuestionItem> process() { List<QuestionItem> qItems = new ArrayList<QuestionItem>(); try { List<DocInfos> docInfoList = getDocInfos(); if (docInfoList != null) { for (DocInfos docInfos : docInfoList) { List<QuestionItem> processdItems = process(docInfos); qItems.addAll(processdItems); dbInstance.commit(); } } } catch (IOException e) { log.error("", e); } return qItems; } private List<QuestionItem> process(DocInfos docInfos) { List<QuestionItem> qItems = new ArrayList<>(); if (docInfos.doc != null) { List<ItemInfos> itemInfos = getItemList(docInfos); for (ItemInfos itemInfo : itemInfos) { QuestionItemImpl qItem = processItem(docInfos, itemInfo, null); if (qItem != null) { processFiles(qItem, itemInfo, docInfos); qItem = questionItemDao.merge(qItem); qItems.add(qItem); } } } return qItems; } protected List<ItemInfos> getItemList(DocInfos doc) { Document document = doc.getDocument(); List<ItemInfos> itemElements = new ArrayList<ItemInfos>(); Element item = (Element) document.selectSingleNode("/questestinterop/item"); Element assessment = (Element) document.selectSingleNode("/questestinterop/assessment"); if (item != null) { ItemInfos itemInfos = new ItemInfos(item, true); Element comment = (Element) document.selectSingleNode("/questestinterop/qticomment"); String qtiComment = getText(comment); itemInfos.setComment(qtiComment); itemElements.add(itemInfos); } else if (assessment != null) { @SuppressWarnings("unchecked") List<Element> items = assessment.selectNodes("//item"); for (Element it : items) { itemElements.add(new ItemInfos(it, false)); } } return itemElements; } protected QuestionItemImpl processItem(DocInfos docInfos, ItemInfos itemInfos, ItemAndMetadata metadata) { Element itemEl = itemInfos.getItemEl(); String comment = itemInfos.getComment(); String originalFilename = null; if (itemInfos.isOriginalItem()) { originalFilename = docInfos.filename; } return processItem(itemEl, comment, originalFilename, null, null, docInfos, metadata); } protected QuestionItemImpl processItem(Element itemEl, String comment, String originalItemFilename, String editor, String editorVersion, DocInfos docInfos, ItemAndMetadata metadata) { //filename String filename; String ident = getAttributeValue(itemEl, "ident"); if (originalItemFilename != null) { filename = originalItemFilename; } else if (StringHelper.containsNonWhitespace(ident)) { filename = StringHelper.transformDisplayNameToFileSystemName(ident) + ".xml"; } else { filename = "item.xml"; } String dir = qpoolFileStorage.generateDir(); //title String title = getAttributeValue(itemEl, "title"); if (!StringHelper.containsNonWhitespace(title)) { title = ident; } if (!StringHelper.containsNonWhitespace(title)) { title = importedFilename; } QuestionItemImpl poolItem = questionItemDao.create(title, QTIConstants.QTI_12_FORMAT, dir, filename); //description poolItem.setDescription(comment); //language from default poolItem.setLanguage(defaultLocale.getLanguage()); //question type first boolean ooFormat = processItemQuestionType(poolItem, ident, itemEl); if (StringHelper.containsNonWhitespace(editor)) { poolItem.setEditor(editor); poolItem.setEditor(editorVersion); } else if (ooFormat) { poolItem.setEditor("OpenOLAT"); } //if question type not found, can be overridden by the metadatas processItemMetadata(poolItem, itemEl); if (poolItem.getType() == null) { QItemType defType = qItemTypeDao.loadByType(QuestionType.UNKOWN.name()); poolItem.setType(defType); } if (docInfos != null) { processSidecarMetadata(poolItem, docInfos); } if (metadata != null) { processItemMetadata(poolItem, metadata); } questionItemDao.persist(owner, poolItem); return poolItem; } private void processItemMetadata(QuestionItemImpl poolItem, ItemAndMetadata metadata) { //non heuristic set of question type int questionType = metadata.getQuestionType(); if (questionType >= 0) { String typeStr; switch (questionType) { case Question.TYPE_MC: typeStr = QuestionType.MC.name(); break; case Question.TYPE_SC: typeStr = QuestionType.SC.name(); break; case Question.TYPE_FIB: typeStr = QuestionType.FIB.name(); break; case Question.TYPE_ESSAY: typeStr = QuestionType.ESSAY.name(); break; default: typeStr = null; } if (typeStr != null) { QItemType type = qItemTypeDao.loadByType(typeStr); if (type != null) { poolItem.setType(type); } } } String coverage = metadata.getCoverage(); if (StringHelper.containsNonWhitespace(coverage)) { poolItem.setCoverage(coverage); } String language = metadata.getLanguage(); if (StringHelper.containsNonWhitespace(language)) { poolItem.setLanguage(language); } String keywords = metadata.getKeywords(); if (StringHelper.containsNonWhitespace(keywords)) { poolItem.setKeywords(keywords); } String taxonomyPath = metadata.getTaxonomyPath(); if (StringHelper.containsNonWhitespace(taxonomyPath)) { QTIMetadataConverter converter = new QTIMetadataConverter(qItemTypeDao, qLicenseDao, taxonomyLevelDao, qEduContextDao); TaxonomyLevel taxonomyLevel = converter.toTaxonomy(taxonomyPath); poolItem.setTaxonomyLevel(taxonomyLevel); } String level = metadata.getLevel(); if (StringHelper.containsNonWhitespace(level)) { QTIMetadataConverter converter = new QTIMetadataConverter(qItemTypeDao, qLicenseDao, taxonomyLevelDao, qEduContextDao); QEducationalContext educationalContext = converter.toEducationalContext(level); poolItem.setEducationalContext(educationalContext); } String time = metadata.getTypicalLearningTime(); if (StringHelper.containsNonWhitespace(time)) { poolItem.setEducationalLearningTime(time); } String editor = metadata.getEditor(); if (StringHelper.containsNonWhitespace(editor)) { poolItem.setEditor(editor); } String editorVersion = metadata.getEditorVersion(); if (StringHelper.containsNonWhitespace(editorVersion)) { poolItem.setEditorVersion(editorVersion); } int numOfAnswerAlternatives = metadata.getNumOfAnswerAlternatives(); if (numOfAnswerAlternatives > 0) { poolItem.setNumOfAnswerAlternatives(numOfAnswerAlternatives); } poolItem.setDifficulty(metadata.getDifficulty()); poolItem.setDifferentiation(metadata.getDifferentiation()); poolItem.setStdevDifficulty(metadata.getStdevDifficulty()); String license = metadata.getLicense(); if (StringHelper.containsNonWhitespace(license)) { QTIMetadataConverter converter = new QTIMetadataConverter(qItemTypeDao, qLicenseDao, taxonomyLevelDao, qEduContextDao); QLicense qLicense = converter.toLicense(license); poolItem.setLicense(qLicense); } } private void processItemMetadata(QuestionItemImpl poolItem, Element itemEl) { @SuppressWarnings("unchecked") List<Element> qtiMetadataFieldList = itemEl.selectNodes("./itemmetadata/qtimetadata/qtimetadatafield"); for (Element qtiMetadataField : qtiMetadataFieldList) { Element labelEl = (Element) qtiMetadataField.selectSingleNode("./fieldlabel"); Element entryEl = (Element) qtiMetadataField.selectSingleNode("./fieldentry"); if (labelEl != null && entryEl != null) { processMetadataField(poolItem, labelEl, entryEl); } } } /** * <ul> * <li>qmd_computerscored</li> * <li>qmd_feedbackpermitted</li> * <li>qmd_hintspermitted</li> * <li>qmd_itemtype -> (check is made on the content of the item)</li> * <li>qmd_levelofdifficulty -> educational context</li> * <li>qmd_maximumscore</li> * <li>qmd_renderingtype</li> * <li>qmd_responsetype</li> * <li>qmd_scoringpermitted</li> * <li>qmd_solutionspermitted</li> * <li>qmd_status</li> * <li>qmd_timedependence</li> * <li>qmd_timelimit</li> * <li>qmd_toolvendor -> editor</li> * <li>qmd_topic</li> * <li>qmd_material</li> * <li>qmd_typeofsolution</li> * <li>qmd_weighting</li> * </ul> * @param poolItem * @param labelEl * @param entryEl */ private void processMetadataField(QuestionItemImpl poolItem, Element labelEl, Element entryEl) { String label = labelEl.getText(); String entry = entryEl.getText(); if (QTIConstants.META_LEVEL_OF_DIFFICULTY.equals(label)) { if (StringHelper.containsNonWhitespace(entry)) { QEducationalContext context = qEduContextDao.loadByLevel(entry); if (context == null) { context = qEduContextDao.create(entry, true); } poolItem.setEducationalContext(context); } } else if (QTIConstants.META_ITEM_TYPE.equals(label)) { if (poolItem.getType() == null && StringHelper.containsNonWhitespace(entry)) { //some heuristic String typeStr = entry; if (typeStr.equalsIgnoreCase("MCQ") || typeStr.equalsIgnoreCase("Multiple choice")) { typeStr = QuestionType.MC.name(); } else if (typeStr.equalsIgnoreCase("SCQ") || typeStr.equalsIgnoreCase("Single choice")) { typeStr = QuestionType.SC.name(); } else if (typeStr.equalsIgnoreCase("fill-in") || typeStr.equals("Fill-in-the-Blank") || typeStr.equalsIgnoreCase("Fill-in-Blank") || typeStr.equalsIgnoreCase("Fill In the Blank")) { typeStr = QuestionType.FIB.name(); } else if (typeStr.equalsIgnoreCase("Essay")) { typeStr = QuestionType.ESSAY.name(); } QItemType type = qItemTypeDao.loadByType(entry); if (type == null) { type = qItemTypeDao.create(entry, true); } poolItem.setType(type); } } else if (QTIConstants.META_TOOLVENDOR.equals(label)) { poolItem.setEditor(entry); } } /** * Save the item element in a <questestinterop> cartridge if needed * @param item * @param itemEl */ protected void processFiles(QuestionItemImpl item, ItemInfos itemInfos, DocInfos docInfos) { if (itemInfos.originalItem) { processItemFiles(item, docInfos); } else { //an assessment package processAssessmentFiles(item, itemInfos); } } protected void processAssessmentFiles(QuestionItemImpl item, ItemInfos itemInfos) { //a package with an item String dir = item.getDirectory(); String rootFilename = item.getRootFilename(); VFSContainer container = qpoolFileStorage.getContainer(dir); VFSLeaf endFile = container.createChildLeaf(rootFilename); //embed in <questestinterop> DocumentFactory df = DocumentFactory.getInstance(); Document itemDoc = df.createDocument(); Element questestinteropEl = df.createElement(QTIDocument.DOCUMENT_ROOT); itemDoc.setRootElement(questestinteropEl); Element deepClone = (Element) itemInfos.getItemEl().clone(); questestinteropEl.add(deepClone); //write try { OutputStream os = endFile.getOutputStream(false); ; XMLWriter xw = new XMLWriter(os, new OutputFormat(" ", true)); xw.write(itemDoc.getRootElement()); xw.close(); os.close(); } catch (IOException e) { log.error("", e); } //there perhaps some other materials if (importedFilename.toLowerCase().endsWith(".zip")) { processAssessmentMaterials(deepClone, container); } } private void processAssessmentMaterials(Element itemEl, VFSContainer container) { List<String> materials = getMaterials(itemEl); try { InputStream in = new FileInputStream(importedFile); ZipInputStream zis = new ZipInputStream(in); ZipEntry entry; try { while ((entry = zis.getNextEntry()) != null) { String name = entry.getName(); if (materials.contains(name)) { VFSLeaf leaf = container.createChildLeaf(name); OutputStream out = leaf.getOutputStream(false); BufferedOutputStream bos = new BufferedOutputStream(out); FileUtils.cpio(new BufferedInputStream(zis), bos, "unzip:" + entry.getName()); bos.flush(); bos.close(); out.close(); } } } catch (Exception e) { log.error("", e); } finally { IOUtils.closeQuietly(zis); IOUtils.closeQuietly(in); } } catch (IOException e) { log.error("", e); } } @SuppressWarnings("unchecked") protected List<String> getMaterials(Element el) { List<String> materialPath = new ArrayList<String>(); //mattext List<Element> mattextList = el.selectNodes(".//mattext"); for (Element mat : mattextList) { Attribute texttypeAttr = mat.attribute("texttype"); if (texttypeAttr != null) { String texttype = texttypeAttr.getValue(); if ("text/html".equals(texttype)) { String content = mat.getStringValue(); findMaterialInMatText(content, materialPath); } } } //matimage uri List<Element> matList = new ArrayList<Element>(); matList.addAll(el.selectNodes(".//matimage")); matList.addAll(el.selectNodes(".//mataudio")); matList.addAll(el.selectNodes(".//matvideo")); for (Element mat : matList) { Attribute uriAttr = mat.attribute("uri"); String uri = uriAttr.getValue(); materialPath.add(uri); } return materialPath; } /** * Parse the content and collect the images source * @param content * @param materialPath */ protected void findMaterialInMatText(String content, List<String> materialPath) { try { SAXParser parser = new SAXParser(); HTMLHandler contentHandler = new HTMLHandler(materialPath); parser.setContentHandler(contentHandler); parser.parse(new InputSource(new StringReader(content))); } catch (SAXException e) { log.error("", e); } catch (IOException e) { log.error("", e); } catch (Exception e) { log.error("", e); } } private static class HTMLHandler extends DefaultHandler { private final List<String> materialPath; private StringBuffer scriptBuffer; public HTMLHandler(List<String> materialPath) { this.materialPath = materialPath; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { String elem = localName.toLowerCase(); if ("img".equals(elem)) { String imgSrc = attributes.getValue("src"); if (StringHelper.containsNonWhitespace(imgSrc)) { materialPath.add(imgSrc); } } else if ("script".equals(elem)) { scriptBuffer = new StringBuffer(); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (scriptBuffer != null) { scriptBuffer.append(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { String elem = localName.toLowerCase(); if ("script".equals(elem)) { String content = scriptBuffer == null ? "" : scriptBuffer.toString(); processScriptContent(content); scriptBuffer = null; } } private void processScriptContent(String content) { int markerIndex = content.indexOf(OPENOLAT_MOVIE_MARKER); if (markerIndex >= 0) { int beginIndex = markerIndex + OPENOLAT_MOVIE_MARKER.length(); char quote = content.charAt(beginIndex); int endIndex = content.indexOf(quote, beginIndex + 1); if (endIndex > beginIndex) { String media = content.substring(beginIndex + 1, endIndex); if (StringHelper.containsNonWhitespace(media)) { materialPath.add(media.trim()); } } } } } /** * Process the file of an item's package * @param item * @param itemInfos */ protected void processItemFiles(QuestionItemImpl item, DocInfos docInfos) { //a package with an item String dir = item.getDirectory(); String rootFilename = item.getRootFilename(); VFSContainer container = qpoolFileStorage.getContainer(dir); if (docInfos != null && docInfos.getRoot() != null) { try { Path destDir = ((LocalImpl) container).getBasefile().toPath(); //unzip to container Path path = docInfos.getRoot(); Files.walkFileTree(path, new CopyVisitor(path, destDir, new YesMatcher())); } catch (IOException e) { log.error("", e); } } else if (importedFilename.toLowerCase().endsWith(".zip")) { ZipUtil.unzipStrict(importedFile, container); } else { VFSLeaf endFile = container.createChildLeaf(rootFilename); OutputStream out = null; FileInputStream in = null; try { out = endFile.getOutputStream(false); in = new FileInputStream(importedFile); IOUtils.copy(in, out); } catch (IOException e) { log.error("", e); } finally { IOUtils.closeQuietly(out); IOUtils.closeQuietly(in); } } } private boolean processSidecarMetadata(QuestionItemImpl item, DocInfos docInfos) { InputStream metadataIn = null; try { Path path = docInfos.root; if (path != null && path.getFileName() != null) { Path metadata = path.resolve(path.getFileName().toString() + "_metadata.xml"); metadataIn = Files.newInputStream(metadata); SAXReader reader = new SAXReader(); Document document = reader.read(metadataIn); Element rootElement = document.getRootElement(); QTIMetadataConverter enricher = new QTIMetadataConverter(rootElement, qItemTypeDao, qLicenseDao, taxonomyLevelDao, qEduContextDao); enricher.toQuestion(item); } return true; } catch (NoSuchFileException e) { //nothing to do return true; } catch (Exception e) { log.error("", e); return false; } finally { IOUtils.closeQuietly(metadataIn); } } private boolean processItemQuestionType(QuestionItemImpl poolItem, String ident, Element itemEl) { boolean openolatFormat = false; //question type: mc, sc... QuestionType type = null; //test with openolat ident if (ident != null && ident.startsWith(ItemParser.ITEM_PREFIX_SCQ)) { type = QuestionType.SC; openolatFormat = true; } else if (ident != null && ident.startsWith(ItemParser.ITEM_PREFIX_MCQ)) { type = QuestionType.MC; openolatFormat = true; } else if (ident != null && ident.startsWith(ItemParser.ITEM_PREFIX_FIB)) { type = QuestionType.FIB; openolatFormat = true; } else if (ident != null && ident.startsWith(ItemParser.ITEM_PREFIX_ESSAY)) { type = QuestionType.ESSAY; openolatFormat = true; } else if (ident != null && ident.startsWith(ItemParser.ITEM_PREFIX_KPRIM)) { type = QuestionType.KPRIM; openolatFormat = true; } else if (itemEl.selectNodes("//render_choice").size() == 1) { Element lidEl = (Element) itemEl.selectSingleNode("//response_lid"); String rcardinality = getAttributeValue(lidEl, "rcardinality"); if ("Single".equals(rcardinality)) { type = QuestionType.SC; } else if ("Multiple".equals(rcardinality)) { type = QuestionType.MC; } } else if (itemEl.selectNodes("//render_fib").size() == 1) { type = QuestionType.FIB; } if (type != null) { QItemType itemType = qItemTypeDao.loadByType(type.name()); poolItem.setType(itemType); } return openolatFormat; } private String getAttributeValue(Element el, String attrName) { if (el == null) return null; Attribute attr = el.attribute(attrName); return (attr == null) ? null : attr.getStringValue(); } private String getText(Element el) { if (el == null) return null; return el.getText(); } protected List<DocInfos> getDocInfos() throws IOException { List<DocInfos> doc; if (importedFilename.toLowerCase().endsWith(".zip")) { //doc = traverseZip(importedFile); doc = traverseZip_nio(importedFile); } else { doc = Collections.singletonList(traverseFile(importedFile)); } return doc; } private DocInfos traverseFile(File file) throws IOException { InputStream in = new FileInputStream(file); try { Document doc = readXml(in); if (doc != null) { DocInfos d = new DocInfos(); d.doc = doc; d.filename = file.getName(); return d; } return null; } catch (Exception e) { log.error("", e); return null; } finally { IOUtils.closeQuietly(in); } } /* private List<DocInfos> traverseZip(File file) throws IOException { InputStream in = new FileInputStream(file); ZipInputStream zis = new ZipInputStream(in); List<DocInfos> docInfos = new ArrayList<>(); ZipEntry entry; try { while ((entry = zis.getNextEntry()) != null) { String name = entry.getName(); if(name != null && name.toLowerCase().endsWith(".xml")) { Document doc = readXml(new ShieldInputStream(zis)); if(doc != null) { DocInfos d = new DocInfos(); d.doc = doc; d.filename = name; docInfos.add(d); } } } } catch(Exception e) { log.error("", e); } finally { IOUtils.closeQuietly(zis); IOUtils.closeQuietly(in); } return docInfos; } */ private List<DocInfos> traverseZip_nio(File file) throws IOException { List<DocInfos> docInfos = new ArrayList<>(); Path fPath = FileSystems.newFileSystem(file.toPath(), null).getPath("/"); if (fPath != null) { DocInfosVisitor visitor = new DocInfosVisitor(); Files.walkFileTree(fPath, visitor); List<Path> xmlFiles = visitor.getXmlFiles(); for (Path xmlFile : xmlFiles) { InputStream in = Files.newInputStream(xmlFile); Document doc = readXml(in); if (doc != null) { DocInfos d = new DocInfos(); d.setDocument(doc); d.setRoot(xmlFile.getParent()); d.setFilename(xmlFile.getFileName().toString()); docInfos.add(d); } } } return docInfos; } public static class DocInfosVisitor extends SimpleFileVisitor<Path> { private final List<Path> xmlFiles = new ArrayList<>(); public List<Path> getXmlFiles() { return xmlFiles; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String name = file.getFileName().toString(); if (name != null && name.toLowerCase().endsWith(".xml")) { xmlFiles.add(file); } return FileVisitResult.CONTINUE; } } private Document readXml(InputStream in) { Document doc = null; try { XMLParser xmlParser = new XMLParser(new IMSEntityResolver()); doc = xmlParser.parse(in, false); return doc; } catch (Exception e) { return null; } } public static class ItemInfos { private String comment; private final Element itemEl; private final boolean originalItem; public ItemInfos(Element itemEl, boolean originalItem) { this.itemEl = itemEl; this.originalItem = originalItem; } public Element getItemEl() { return itemEl; } public boolean isOriginalItem() { return originalItem; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } } public static class DocInfos { private Document doc; private String filename; private Path root; private Path metadata; private String qtiComment; public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public Document getDocument() { return doc; } public void setDocument(Document doc) { this.doc = doc; } public Path getMetadata() { return metadata; } public void setMetadata(Path metadata) { this.metadata = metadata; } public Path getRoot() { return root; } public void setRoot(Path root) { this.root = root; } public String getQtiComment() { return qtiComment; } public void setQtiComment(String qtiComment) { this.qtiComment = qtiComment; } } }