org.olat.ims.qti.qpool.ItemFileResourceValidator.java Source code

Java tutorial

Introduction

Here is the source code for org.olat.ims.qti.qpool.ItemFileResourceValidator.java

Source

/**
 * <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.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentType;
import org.dom4j.io.SAXReader;
import org.dom4j.io.SAXValidator;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.io.ShieldInputStream;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.ims.resources.IMSEntityResolver;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 * 
 * Initial date: 27.02.2013<br>
 * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
 *
 */
public class ItemFileResourceValidator {

    private static final OLog log = Tracing.createLoggerFor(ItemFileResourceValidator.class);

    public boolean validate(String filename, File file) {
        if (file == null || !file.exists())
            return false;

        InputStream in = null;
        try {
            in = new FileInputStream(file);
            return validate(filename, in);
        } catch (FileNotFoundException e) {
            return false;
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    public boolean validate(String filename, VFSLeaf file) {
        if (file == null || !file.exists())
            return false;

        InputStream in = null;
        try {
            in = file.getInputStream();
            return validate(filename, in);
        } catch (Exception e) {
            return false;
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    public boolean validate(String filename, InputStream in) {
        boolean valid = false;

        if (filename.toLowerCase().endsWith(".xml")) {
            valid = validateXml(in);
            IOUtils.closeQuietly(in);
        } else if (filename.toLowerCase().endsWith(".zip")) {
            ZipInputStream oZip = new ZipInputStream(in);
            try {
                ZipEntry oEntr = oZip.getNextEntry();
                while (oEntr != null) {
                    if (!oEntr.isDirectory()) {
                        if (validateXml(new ShieldInputStream(oZip))) {
                            valid = true;
                        }
                    }
                    oZip.closeEntry();
                    oEntr = oZip.getNextEntry();
                }
            } catch (Exception e) {
                log.error("", e);
                valid = false;
            } finally {
                IOUtils.closeQuietly(oZip);
                IOUtils.closeQuietly(in);
            }
        }

        return valid;
    }

    private boolean validateXml(InputStream in) {
        boolean valid = false;
        Document doc = readDocument(in);
        if (doc != null) {
            DocumentType docType = doc.getDocType();
            if (docType == null) {
                doc.addDocType("questestinterop", null, "ims_qtiasiv1p2p1.dtd");
            }
            valid = validateDocument(doc);
        }
        return valid;
    }

    private Document readDocument(InputStream in) {
        try {
            SAXReader reader = new SAXReader();
            reader.setEntityResolver(new IMSEntityResolver());
            reader.setValidation(false);
            return reader.read(in, "");
        } catch (Exception e) {
            return null;
        }
    }

    private boolean validateDocument(Document in) {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setValidating(true);
            factory.setNamespaceAware(true);

            SimpleErrorHandler errorHandler = new SimpleErrorHandler();
            ItemContentHandler contentHandler = new ItemContentHandler();

            SAXParser parser = factory.newSAXParser();
            XMLReader reader = parser.getXMLReader();
            reader.setEntityResolver(new IMSEntityResolver());
            reader.setErrorHandler(errorHandler);
            reader.setContentHandler(contentHandler);

            SAXValidator validator = new SAXValidator(reader);
            validator.validate(in);

            return errorHandler.isValid() && contentHandler.isItem();
        } catch (ParserConfigurationException e) {
            return false;
        } catch (SAXException e) {
            return false;
        } catch (Exception e) {
            return false;
        }
    }

    private static class SimpleErrorHandler implements ErrorHandler {
        private int error = 0;

        public boolean isValid() {
            return error == 0;
        }

        @Override
        public void warning(SAXParseException exception) throws SAXException {
            //
        }

        @Override
        public void error(SAXParseException exception) throws SAXException {
            log.warn("Parsing error importing question item in pool: ", exception);
            error++;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
            error++;
        }
    }

    private static class ItemContentHandler extends DefaultHandler {
        private boolean interop;
        private boolean item;

        public boolean isItem() {
            return item;
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {

            if ("questestinterop".equals(qName)) {
                interop = true;
            } else if ("item".equals(localName) || "item".equals(qName)) {
                if (interop) {
                    item = true;
                }
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ("questestinterop".equals(qName)) {
                interop = false;
            }
        }
    }
}