org.jboss.maven.plugins.qstools.checkers.ValidXMLSchemaChecker.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.maven.plugins.qstools.checkers.ValidXMLSchemaChecker.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * 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 org.jboss.maven.plugins.qstools.checkers;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

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

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.utils.io.FileUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.jboss.maven.plugins.qstools.QSToolsException;
import org.jboss.maven.plugins.qstools.config.ConfigurationProvider;
import org.jboss.maven.plugins.qstools.config.Resources;
import org.jboss.maven.plugins.qstools.config.Rules;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * 
 * @author rafaelbenevides
 */
@Component(role = QSChecker.class, hint = "ValidXMLSchemaChecker")
public class ValidXMLSchemaChecker implements QSChecker {

    private int violationsQtd;

    @Requirement
    private ConfigurationProvider configurationProvider;

    @Requirement
    private Resources resources;

    private String checkerMessage;

    private Log log;

    @Override
    public String getCheckerDescription() {
        return "Verifies if XML files are using a valid according to XML Schema or DTD";
    }

    private void addViolation(String fileAsString, int line, String message, Map<String, List<Violation>> results) {
        violationsQtd++;
        if (results.get(fileAsString) == null) {
            results.put(fileAsString, new ArrayList<Violation>());
        }
        results.get(fileAsString).add(new Violation(ValidXMLSchemaChecker.class, line, message));
    }

    @Override
    public Map<String, List<Violation>> check(MavenProject project, MavenSession mavenSession,
            List<MavenProject> reactorProjects, Log log) throws QSToolsException {
        log.info("--> This Checker can take several minutes to run");
        this.log = log;
        Map<String, List<Violation>> results = new TreeMap<String, List<Violation>>();
        Rules rules = configurationProvider.getQuickstartsRules(project.getGroupId());
        try {
            if (rules.isCheckerIgnored(this.getClass())) {
                checkerMessage = "This checker is ignored for this groupId in config file.";
            } else {
                // get all xml to process but excludes hidden files and /target and /bin folders
                List<File> xmlFiles = FileUtils.getFiles(project.getBasedir(), "**/*.xml", rules.getExcludes());
                SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                Schema schema = schemaFactory.newSchema();
                for (File xml : xmlFiles) {
                    // Get relative path based on maven work dir
                    String rootDirectory = (mavenSession.getExecutionRootDirectory() + File.separator).replace("\\",
                            "\\\\");
                    String fileAsString = xml.getAbsolutePath().replace(rootDirectory, "");
                    Validator validator = schema.newValidator();
                    validator.setResourceResolver(new URLBasedResourceResolver(xml));
                    validator.setErrorHandler(new XMLErrorHandler(fileAsString, results));

                    log.info("Validating " + fileAsString);
                    try {
                        validator.validate(new StreamSource(new BufferedInputStream(new FileInputStream(xml))));
                    } catch (SAXException e) {
                        // validator.validate can throw a SAXException coming from the ErrorHandler
                        addViolation(fileAsString, 0, e.getMessage(), results);
                    }
                }
                if (getCheckerMessage() != null) {
                    log.info("--> Checker Message: " + getCheckerMessage());
                }
                if (violationsQtd > 0) {
                    log.info("There are " + violationsQtd + " checkers violations");
                }
            }
        } catch (Exception e) {
            throw new QSToolsException(e);
        }
        return results;

    }

    @Override
    public int getViolatonsQtd() {
        return violationsQtd;
    }

    @Override
    public void resetViolationsQtd() {
        violationsQtd = 0;
    }

    @Override
    public String getCheckerMessage() {
        return checkerMessage;
    }

    private class XMLErrorHandler implements ErrorHandler {

        private Map<String, List<Violation>> results;
        private String fileAsString;

        public XMLErrorHandler(String fileAsString, Map<String, List<Violation>> results) {
            this.results = results;
            this.fileAsString = fileAsString;
        }

        @Override
        public void warning(SAXParseException exception) throws SAXException {
            addViolation(fileAsString, exception.getLineNumber(), exception.getMessage(), results);
        }

        @Override
        public void error(SAXParseException exception) throws SAXException {
            addViolation(fileAsString, exception.getLineNumber(), exception.getMessage(), results);
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
            addViolation(fileAsString, exception.getLineNumber(), exception.getMessage(), results);
        }

    }

    private class URLBasedResourceResolver implements LSResourceResolver {

        private File xml;

        public URLBasedResourceResolver(File xml) {
            this.xml = xml;
        }

        @Override
        public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId,
                String baseURI) {
            String msg = String.format("Resolve: type=%s, ns=%s, publicId=%s, systemId=%s, baseUri=%s.", type,
                    namespaceURI, publicId, systemId, baseURI);
            log.debug(msg);
            MyLSInput input = new MyLSInput();
            input.setPublicId(publicId);
            input.setSystemId(systemId);
            try {
                if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
                    if (namespaceURI == null && systemId != null) {
                        FileInputStream fis = new FileInputStream(new File(xml.getParent(), systemId));
                        input.setByteStream(fis);
                        input.setSystemId(systemId);
                    } else if (namespaceURI != null) {
                        URI uri = new URI(baseURI == null ? "" : baseURI);
                        URL url = uri.resolve(systemId == null ? "" : systemId).toURL();
                        if (url.getProtocol().equals("http") && url.toString().endsWith(".xsd")) {
                            InputStream is = resources.getFileInputStream(url);
                            input.setBaseURI(baseURI);
                            input.setByteStream(is);
                        }
                    }
                }
            } catch (IllegalArgumentException e) {
                // It's ok for XMLs without systemId and BaseURI
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return input;
        }

        private class MyLSInput implements LSInput {

            private Reader characterStream;

            private InputStream inputStream;

            private String stringData;

            private String systemId;

            private String publicId;

            private String baseURI;

            private String encoding;

            private boolean certified;

            @Override
            public Reader getCharacterStream() {
                return characterStream;
            }

            @Override
            public void setCharacterStream(Reader characterStream) {
                this.characterStream = characterStream;
            }

            @Override
            public InputStream getByteStream() {
                return inputStream;
            }

            @Override
            public void setByteStream(InputStream byteStream) {
                this.inputStream = byteStream;
            }

            @Override
            public String getStringData() {
                return stringData;
            }

            @Override
            public void setStringData(String stringData) {
                this.stringData = stringData;
            }

            @Override
            public String getSystemId() {
                return systemId;
            }

            @Override
            public void setSystemId(String systemId) {
                this.systemId = systemId;
            }

            @Override
            public String getPublicId() {
                return publicId;
            }

            @Override
            public void setPublicId(String publicId) {
                this.publicId = publicId;

            }

            @Override
            public String getBaseURI() {
                return baseURI;
            }

            @Override
            public void setBaseURI(String baseURI) {
                this.baseURI = baseURI;

            }

            @Override
            public String getEncoding() {
                return encoding;
            }

            @Override
            public void setEncoding(String encoding) {
                this.encoding = encoding;
            }

            @Override
            public boolean getCertifiedText() {
                return certified;
            }

            @Override
            public void setCertifiedText(boolean certifiedText) {
                this.certified = certifiedText;
            }

        }
    }

}