com.c4om.autoconf.ulysses.configanalyzer.environmentchecker.XSDFriendlyValidatorBasedChecker.java Source code

Java tutorial

Introduction

Here is the source code for com.c4om.autoconf.ulysses.configanalyzer.environmentchecker.XSDFriendlyValidatorBasedChecker.java

Source

/*
Copyright 2014 Universidad Politcnica de Madrid - Center for Open Middleware (http://www.centeropenmiddleware.com)
    
Licensed under the Apache 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.apache.org/licenses/LICENSE-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 com.c4om.autoconf.ulysses.configanalyzer.environmentchecker;

import static com.c4om.utils.xmlutils.JavaXMLUtils.*;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.c4om.autoconf.ulysses.configanalyzer.core.datastructures.ConfigurationAnalysisContext;
import com.c4om.autoconf.ulysses.configanalyzer.core.datastructures.ExtractedConfiguration;
import com.c4om.autoconf.ulysses.configanalyzer.core.exceptions.EnvironmentCheckingException;
import com.c4om.autoconf.ulysses.configanalyzer.core.exceptions.EnvironmentException;
import com.c4om.autoconf.ulysses.configanalyzer.environmentchecker.exceptions.IncorrectXMLFilesException;
import com.c4om.autoconf.ulysses.configanalyzer.environmentchecker.exceptions.XMLNotValidAgainstXSDException;
import com.c4om.autoconf.ulysses.interfaces.Target;
import com.c4om.xsdfriendlyvalidator.ValidationResults;
import com.c4om.xsdfriendlyvalidator.XSDFriendlyValidationException;
import com.c4om.xsdfriendlyvalidator.XSDFriendlyValidator;
import com.c4om.xsdfriendlyvalidator.XSDFriendlyValidatorImpl;

/**
 * Environment checker that performs a check based on a XSD validation. 
 * XSD files are expected to have one of the names specified at a list and to be placed 
 * into a subdirectory such that its path relative to the XSD set root folder 
 * is equal to the one of the validated file (the name of the file will be the 
 * name of the folder containing the schemas).
 * The used XSD validator is XSDFriendlyValidator.
 * @author Pablo Alonso Rodrguez (Center for Open Middleware - UPM)
 *
 */
public class XSDFriendlyValidatorBasedChecker implements EnvironmentChecker {

    /**
     * Prefix for the keys of properties that contain the paths to the respective xsd sets.
     * Those properties MUST be of the form: 
     * <i>PROPERTY_KEY_PREFFIX_XSD_SETS_LOCATIONS</i><i>xsdSetName</i>
     */
    private static final String PROPERTY_KEY_PREFFIX_XSD_SETS_LOCATIONS = "environmentchecker.xsdSetsLocations.";

    /**
     * XSD set to get XSDs from.
     */
    private String xsdSetName;

    /**
     * Names of XSD files to look for.
     */
    private List<String> xsdNames;

    /**
     * The target to work at.
     */
    private Target target;

    /**
     * {@link FileFileFilter}, that only accepts XML files.
     */
    private static final FileFilter XML_FILE_FILTER = new AndFileFilter(new SuffixFileFilter(".xml"),
            FileFileFilter.FILE);

    /**
     * Constructor
     * @param xsdSetName the name of the included XSD set to use
     * @param xsdNames the list of allowed XSD names
     * @param target the {@link Target} to work on
     */
    public XSDFriendlyValidatorBasedChecker(String xsdSetName, List<String> xsdNames, Target target) {
        this.xsdSetName = xsdSetName;
        this.xsdNames = xsdNames;
        this.target = target;
    }

    /**
     * Constructor
     * @param xsdSetName the name of the included XSD set to use
     * @param xsdNames the list of allowed XSD names
     */
    public XSDFriendlyValidatorBasedChecker(String xsdSetName, List<String> xsdNames) {
        this(xsdSetName, xsdNames, null);
    }

    /**
     * This method takes an extracted XML file, looks for its related schema file(s) (if any) and validates it against them
     * @param extractedFile the extracted {@link File} pointing to the document to validate (if possible)
     * @param base the base path where the temporary local copy of the configuration is stored.
     * @param configurationAnalyzerSettings the configuration analyzer settings.
     * @return the {@link ValidationResults} produced when the given file is validated.
     * @throws EnvironmentCheckingException if there is an error that makes impossible to continue the validation
     */
    private ValidationResults processSingleFile(File extractedFile, File base,
            Properties configurationAnalyzerSettings) throws EnvironmentCheckingException {
        try {
            List<InputStream> inputStreamsForXSDs = new ArrayList<>(xsdNames.size());
            XSDFriendlyValidator validator = new XSDFriendlyValidatorImpl();
            for (String xsdName : xsdNames) {
                String relativePath = extractedFile.getAbsolutePath().replaceAll(
                        "^" + Pattern.quote(base.getAbsolutePath()) + "(" + Pattern.quote(File.separator) + ")?",
                        "");
                String currentXsdSetPath = configurationAnalyzerSettings
                        .getProperty(PROPERTY_KEY_PREFFIX_XSD_SETS_LOCATIONS + xsdSetName);
                if (currentXsdSetPath == null) {
                    throw new EnvironmentCheckingException("Property '" + PROPERTY_KEY_PREFFIX_XSD_SETS_LOCATIONS
                            + xsdSetName
                            + "' not found. Please check that it is correctly defined, so that the current xsd set can be found.");
                }
                String inputXSDPath = currentXsdSetPath + "/" + relativePath + "/" + xsdName;
                File inputXSDFile = new File(inputXSDPath);
                if (inputXSDFile.exists()) {
                    InputStream inputStream = new FileInputStream(inputXSDFile);
                    inputStreamsForXSDs.add(inputStream);
                }
            }
            Map<String, Document> schemas = new HashMap<>(inputStreamsForXSDs.size());
            if (inputStreamsForXSDs.isEmpty()) {
                return null; //There are no files to validate
            }
            for (InputStream is : inputStreamsForXSDs) {
                Document schemaDocument = loadW3CDocumentFromInputStream(is);
                String targetNamespace = schemaDocument.getDocumentElement().getAttribute("targetNamespace");
                if (schemas.containsKey(targetNamespace)) {
                    throw new EnvironmentCheckingException(
                            "More than one schema is defined for target namespace '" + targetNamespace + "'");
                }
                schemas.put(targetNamespace, schemaDocument);
            }
            Document instanceDocument = loadW3CDocumentFromInputFile(extractedFile);
            ValidationResults validationResults = validator.validate(instanceDocument, schemas);
            return validationResults;
        } catch (ParserConfigurationException | SAXException | IOException | XSDFriendlyValidationException e) {
            throw new EnvironmentCheckingException(e);
        }

    }

    /**
     * @see com.c4om.autoconf.ulysses.interfaces.configanalyzer.environmentchecker.EnvironmentChecker#checkEnvironment(com.c4om.autoconf.ulysses.interfaces.configanalyzer.core.datastructures.ConfigurationAnalysisContext)
     */
    @Override
    public void checkEnvironment(ConfigurationAnalysisContext context)
            throws EnvironmentException, EnvironmentCheckingException {
        List<XMLNotValidAgainstXSDException> negativeValidationResults = new ArrayList<>();
        for (ExtractedConfiguration<?> extractedConfiguration : context.getExtractedConfigurations()) {
            //If a filtering target is specified, we ignore all the extracted configurations which do not come from it.
            if (target != null && !extractedConfiguration.getTarget().equals(target)) {
                continue;
            }
            Object extractedConfigurationData = extractedConfiguration.getConfigurationData();
            // We check whether this list is a List<File>. It is not so
            // simple, as Java looses information about parametrized types
            // at runtime.
            if (!(extractedConfigurationData instanceof List)) {
                continue;// It is not a list
            }
            List<?> extractedList = (List<?>) extractedConfigurationData;
            if (extractedList.size() == 0 || !(extractedList.get(0) instanceof File)) {
                continue;// This is not the kind of list we were looking
                         // for.
            }
            @SuppressWarnings("unchecked")
            List<File> extractedFilesList = (List<File>) extractedList;
            Properties configurationAnalyzerSettings = context.getConfigurationAnalyzerSettings();
            for (File extractedFile : extractedFilesList) {
                if (XML_FILE_FILTER.accept(extractedFile)) {
                    File base = extractedFile.getParentFile();
                    //Now, we look for the for the schemas related to the file and get input streams to them
                    ValidationResults validationResults = processSingleFile(extractedFile, base,
                            configurationAnalyzerSettings);
                    if (validationResults != null && validationResults.getValidationErrorMessages().size() > 0) {
                        XMLNotValidAgainstXSDException xsdException = new XMLNotValidAgainstXSDException(
                                validationResults);
                        negativeValidationResults.add(xsdException);
                    }
                } else if (extractedFile.isDirectory()) {
                    //The extracted file is a directory, so we traverse it to look for XML files.
                    File base = extractedFile.getParentFile();
                    Collection<File> filesToLookAt = FileUtils.listFiles(extractedFile,
                            (IOFileFilter) XML_FILE_FILTER, TrueFileFilter.INSTANCE);
                    for (File file : filesToLookAt) {
                        //Now, we look for the for the schemas related to the file and get input streams to them
                        ValidationResults validationResults = processSingleFile(file, base,
                                configurationAnalyzerSettings);
                        if (validationResults != null
                                && validationResults.getValidationErrorMessages().size() > 0) {
                            XMLNotValidAgainstXSDException xsdException = new XMLNotValidAgainstXSDException(
                                    validationResults);
                            negativeValidationResults.add(xsdException);
                        }
                    }
                }
            }
        }
        if (negativeValidationResults.size() > 0) {
            throw new IncorrectXMLFilesException(negativeValidationResults);
        }
    }

}