ch.kostceco.tools.siardval.validation.module.impl.ValidationHcontentModuleImpl.java Source code

Java tutorial

Introduction

Here is the source code for ch.kostceco.tools.siardval.validation.module.impl.ValidationHcontentModuleImpl.java

Source

/*== SIARD-Val ===================================================================================
The SIARD-Val application is used for validate SIARD-Files. 
Copyright (C) 2012-2013 Claire Rthlisberger (KOST-CECO), Christian Eugster, Olivier Debenath, 
Peter Schneider (Staatsarchiv Aargau)
--------------------------------------------------------------------------------------------------
SIARD-Val is a development of the KOST-CECO. All rights rest with the KOST-CECO. 
This application is free software: you can redistribute it and/or modify it under the 
terms of the GNU General Public License as published by the Free Software Foundation, 
either version 3 of the License, or (at your option) any later version. 
This application is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the follow GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; 
if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
Boston, MA 02110-1301 USA or see <http://www.gnu.org/licenses/>.
==================================================================================================*/

package ch.kostceco.tools.siardval.validation.module.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.input.SAXBuilder;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import ch.kostceco.tools.siardval.exception.module.ValidationHcontentException;
import ch.kostceco.tools.siardval.service.ConfigurationService;
import ch.kostceco.tools.siardval.validation.ValidationModuleImpl;
import ch.kostceco.tools.siardval.validation.module.ValidationHcontentModule;

/**
 * Validierungsschritt H (Content-Validierung) Sind die XML-Dateien im content
 * valid zu ihrer Schema-Definition (XSD-Dateien)? valid --> tableZ.xml valid zu
 * tableZ.xsd
 * 
 * @author Ec Christian Eugster
 */

public class ValidationHcontentModuleImpl extends ValidationModuleImpl implements ValidationHcontentModule {

    private static final int UNBOUNDED = -1;

    public ConfigurationService configurationService;

    private XMLReader reader;

    public ConfigurationService getConfigurationService() {
        return configurationService;
    }

    public void setConfigurationService(ConfigurationService configurationService) {
        this.configurationService = configurationService;
    }

    @Override
    public boolean validate(File siardDatei) throws ValidationHcontentException {
        boolean valid = true;
        try {
            /*
             * Extract the metadata.xml from the temporary work folder and build
             * a jdom document
             */
            String pathToWorkDir = getConfigurationService().getPathToWorkDir();
            File metadataXml = new File(new StringBuilder(pathToWorkDir).append(File.separator).append("header")
                    .append(File.separator).append("metadata.xml").toString());
            InputStream fin = new FileInputStream(metadataXml);
            SAXBuilder builder = new SAXBuilder();
            Document document = builder.build(fin);
            fin.close();

            /*
             * read the document and for each schema and table entry verify
             * existence in temporary extracted structure
             */
            Namespace ns = Namespace.getNamespace("http://www.bar.admin.ch/xmlns/siard/1.0/metadata.xsd");
            // select schema elements and loop
            List<Element> schemas = document.getRootElement().getChild("schemas", ns).getChildren("schema", ns);
            for (Element schema : schemas) {
                Element schemaFolder = schema.getChild("folder", ns);
                File schemaPath = new File(new StringBuilder(pathToWorkDir).append(File.separator).append("content")
                        .append(File.separator).append(schemaFolder.getText()).toString());
                if (schemaPath.isDirectory()) {
                    Element[] tables = schema.getChild("tables", ns).getChildren("table", ns)
                            .toArray(new Element[0]);
                    for (Element table : tables) {
                        Element tableFolder = table.getChild("folder", ns);
                        File tablePath = new File(new StringBuilder(schemaPath.getAbsolutePath())
                                .append(File.separator).append(tableFolder.getText()).toString());
                        if (tablePath.isDirectory()) {
                            File tableXml = new File(new StringBuilder(tablePath.getAbsolutePath())
                                    .append(File.separator).append(tableFolder.getText() + ".xml").toString());
                            File tableXsd = new File(new StringBuilder(tablePath.getAbsolutePath())
                                    .append(File.separator).append(tableFolder.getText() + ".xsd").toString());
                            if (verifyRowCount(tableXml, tableXsd)) {

                                valid = validate(tableXml, tableXsd) && valid;
                            }
                        }
                    }
                }
            }
        } catch (java.io.IOException ioe) {
            valid = false;
            getMessageService().logError(getTextResourceService().getText(MESSAGE_MODULE_H)
                    + getTextResourceService().getText(MESSAGE_DASHES) + "IOException " + ioe.getMessage());
        } catch (JDOMException e) {
            valid = false;
            getMessageService().logError(getTextResourceService().getText(MESSAGE_MODULE_H)
                    + getTextResourceService().getText(MESSAGE_DASHES) + "JDOMException " + e.getMessage());
        } catch (SAXException e) {
            valid = false;
            getMessageService().logError(getTextResourceService().getText(MESSAGE_MODULE_H)
                    + getTextResourceService().getText(MESSAGE_DASHES) + "SAXException " + e.getMessage());
        }

        return valid;
    }

    private boolean validate(File xmlFile, File schemaLocation) throws SAXException, IOException {
        SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        ValidationErrorHandler errorHandler = new ValidationErrorHandler(xmlFile, schemaLocation);
        Schema schema = factory.newSchema(schemaLocation);
        Validator validator = schema.newValidator();
        validator.setErrorHandler(errorHandler);
        Source source = new StreamSource(xmlFile);
        validator.validate(source);
        return errorHandler.isValid();
    }

    /**
     * Verify the number of rows in the table. If table count >=
     * SIARDVal.conf.xml.table-rows-limit, the xsd minOccurs and maxOccurs
     * values are extracted. If those values are numbers, then the validation is
     * not executed, because the risk of an OutOfMemoryError is given.
     * 
     * @param xmlFile
     * @param schemaLocation
     * @return <code>true</code> if validation should be excecuted, else
     *         <code>false</code>
     * @throws SAXException
     * @throws IOException
     */
    private boolean verifyRowCount(File xmlFile, File schemaLocation) throws SAXException, IOException {
        Range range = getRange(schemaLocation);
        if (range.min == 0 && range.max == UNBOUNDED) {
            return true;
        } else {
            int limit = configurationService.getTableRowsLimit();
            if (range.max > limit) {
                getMessageService().logInfo(getTextResourceService().getText(MESSAGE_MODULE_H)
                        + getTextResourceService().getText(MESSAGE_DASHES) + getTextResourceService()
                                .getText(MESSAGE_MODULE_H_TABLE_NOT_VALIDATED1, xmlFile.getName()));
                getMessageService().logError(getTextResourceService().getText(MESSAGE_MODULE_H)
                        + getTextResourceService().getText(MESSAGE_DASHES) + getTextResourceService().getText(
                                MESSAGE_MODULE_H_TABLE_NOT_VALIDATED2, range.max, limit, schemaLocation.getName()));
            }
            return range.min <= limit && range.max <= limit;
        }
    }

    // private int getRowCount(File xmlFile) throws SAXException, IOException
    // {
    // reader = XMLReaderFactory.createXMLReader();
    // reader.setFeature( "http://xml.org/sax/features/validation", false );
    // reader.setFeature( "http://apache.org/xml/features/validation/schema",
    // false );
    // CountRowsHandler countRowsHandler = new CountRowsHandler();
    // reader.setContentHandler( countRowsHandler );
    // reader.parse( new InputSource(new FileInputStream(xmlFile)) );
    // return countRowsHandler.getRows();
    // }

    private Range getRange(File xsdFile) throws SAXException, IOException {
        Range range = new Range();
        RangeHandler rangeHandler = new RangeHandler();
        try {
            reader = XMLReaderFactory.createXMLReader();
            reader.setFeature("http://xml.org/sax/features/validation", false);
            reader.setFeature("http://apache.org/xml/features/validation/schema", false);
            reader.setContentHandler(rangeHandler);
            reader.parse(new InputSource(new FileInputStream(xsdFile)));
        } catch (BreakException e) {
            range = rangeHandler.getRange();
        }
        return range;
    }

    private class ValidationErrorHandler implements ErrorHandler {
        private boolean valid = true;

        private File xmlFile;

        private File schemaLocation;

        public ValidationErrorHandler(File xmlFile, File schemaLocation) {
            this.xmlFile = xmlFile;
            this.schemaLocation = schemaLocation;
        }

        @Override
        public void error(SAXParseException e) throws SAXException {
            if (valid) {
                valid = false;
            }
            logError(e);
        }

        @Override
        public void fatalError(SAXParseException e) throws SAXException {
            if (valid) {
                valid = false;
            }
            logError(e);
        }

        @Override
        public void warning(SAXParseException e) throws SAXException {
            if (valid) {
                valid = false;
            }
            logError(e);
        }

        private void logError(SAXParseException e) {
            getMessageService().logError(getTextResourceService().getText(MESSAGE_MODULE_H)
                    + getTextResourceService().getText(MESSAGE_DASHES)
                    + getTextResourceService().getText(MESSAGE_MODULE_H_INVALID_ERROR, xmlFile.getName(),
                            schemaLocation.getName(), e.getLineNumber(), e.getColumnNumber(),
                            e.getLocalizedMessage()));
        }

        public boolean isValid() {
            return valid;
        }
    }

    private class CountRowsHandler extends DefaultHandler {
        private int rows = 0;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if (localName.equals("row")) {
                rows++;
            }
        }

        public int getRows() {
            return rows;
        }
    }

    private class RangeHandler extends DefaultHandler {
        private Range range = new Range();

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if ("row".equals(attributes.getValue("name"))) {
                if ("rowType".equals(attributes.getValue("type"))) {
                    this.range.min = getRange(attributes.getValue("minOccurs"));
                    this.range.max = getRange(attributes.getValue("maxOccurs"));
                    throw new BreakException();
                }
            }
        }

        private int getRange(String attributeValue) {
            int value = 1;
            if (attributeValue == null) {
                return value;
            }
            if (attributeValue.equals("unbounded")) {
                return -1;
            }
            try {
                value = Integer.valueOf(attributeValue).intValue();
            } catch (NumberFormatException e) {
            }
            return value;
        }

        public Range getRange() {
            return range;

        }
    }

    private class BreakException extends SAXException {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

    }

    private class Range {
        public int min = 1;

        public int max = 1;
    }
}