org.betaconceptframework.astroboa.configuration.W3CRelatedSchemaEntityResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.betaconceptframework.astroboa.configuration.W3CRelatedSchemaEntityResolver.java

Source

/*
 * Copyright (C) 2005-2012 BetaCONCEPT Limited
 *
 * This file is part of Astroboa.
 *
 * Astroboa is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Astroboa 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
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Astroboa.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.betaconceptframework.astroboa.configuration;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.xml.XMLConstants;

import org.apache.commons.lang.StringUtils;
import org.betaconceptframework.astroboa.api.model.exception.CmsException;
import org.betaconceptframework.astroboa.util.CmsConstants;
import org.slf4j.LoggerFactory;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * When the repository registry is initialized, Astroboa configuration file is loaded and validated
 * against the configuration XML Schema. 
 * 
 * During the validation process, XSDs are validated by the parser. Part of the validation process 
 * is to import all necessary XSDs or DTDs dependencies.
 * Some of these XSDs (XML Schema's XSD, etc) or DTDs are located externally and thus, can be imported 
 * only when an Internet access
 * is available. When this is not the case, XSD parser cannot complete validation and throws an exception.
 *
 * To avoid this situation (which causes a build to fail or even worse does not allow Astroboa to run), 
 * Astroboa identifies whether these files can be accessed and if they cannot, it feeds the parser with 
 * their copy which is located in this directory. 
 * 
 * @author Gregory Chomatas (gchomatas@betaconcept.com)
 * @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
 * 
 */
public class W3CRelatedSchemaEntityResolver implements EntityResolver, LSResourceResolver {

    private String xmlSchemaHomeDir = CmsConstants.FORWARD_SLASH + "META-INF" + CmsConstants.FORWARD_SLASH
            + "xml-schema-dtd";

    private DOMImplementationRegistry registry;

    private Map<String, URL> schemaURLsPerPublicId = new HashMap<String, URL>();

    public W3CRelatedSchemaEntityResolver() {
        try {
            registry = DOMImplementationRegistry.newInstance();
        } catch (Exception e) {
            throw new CmsException(e);
        }
    }

    /**
     * Resolves Entities with the following properties
     * 
     * publicId = http://www.w3.org/XML/1998/namespace
     * systemId = http://www.w3.org/2001/03/xml.xsd
     * 
     * publicId = datatypes
     * systemId = http://www.w3.org/2001/03/datatypes.dtd
     * 
     * publicId = -//W3C//DTD XMLSCHEMA 200102//EN
     * systemId = http://www.w3.org/2001/03/XMLSchema.dtd
     * 
     * If above schemata are not reachable (probably due to a lack of Internet access),
     * they are loaded from the package
     * 
     * @return
     * @throws IOException 
     */
    @Override
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {

        if (StringUtils.equals(systemId, CmsConstants.XML_SCHEMA_LOCATION)) {
            return locateEntity(CmsConstants.XML_SCHEMA_LOCATION, XMLConstants.XML_NS_URI);
        }

        if (StringUtils.equals(systemId, CmsConstants.XML_SCHEMA_DTD_LOCATION)) {
            return locateEntity(CmsConstants.XML_SCHEMA_DTD_LOCATION, "-//W3C//DTD XMLSCHEMA 200102//EN");
        }

        if (StringUtils.equals(systemId, CmsConstants.XML_DATATYPES_DTD_LOCATION)) {
            return locateEntity(CmsConstants.XML_DATATYPES_DTD_LOCATION, "datatypes");
        }

        return null;
    }

    private InputSource locateEntity(String systemId, String publicId) throws IOException {

        URL xsdOrDtdLocation = null;

        if (publicId != null && schemaURLsPerPublicId.containsKey(publicId)) {
            xsdOrDtdLocation = schemaURLsPerPublicId.get(publicId);
        }

        if (systemId == null) {
            return null;
        }

        String xsdOrDtdFilename = (systemId.contains(CmsConstants.FORWARD_SLASH)
                ? StringUtils.substringAfterLast(systemId, CmsConstants.FORWARD_SLASH)
                : systemId);

        //Check if schema is available locally
        if (xsdOrDtdLocation == null) {
            xsdOrDtdLocation = this.getClass()
                    .getResource(xmlSchemaHomeDir + CmsConstants.FORWARD_SLASH + xsdOrDtdFilename);
        }

        //Try on the WEB
        if (xsdOrDtdLocation == null) {
            xsdOrDtdLocation = new URL(systemId);
        }

        try {
            InputSource is = new InputSource(xsdOrDtdLocation.openStream());

            //System Id is the path of this URL
            is.setSystemId(xsdOrDtdLocation.toString());
            is.setPublicId(publicId);

            schemaURLsPerPublicId.put(publicId, xsdOrDtdLocation);

            return is;
        } catch (Throwable isEx) {

            //Log a warning and let the Xerces parser to locate the schema
            LoggerFactory.getLogger(getClass()).warn("Unable to resolve schema for " + publicId + " " + systemId
                    + " in URL " + xsdOrDtdLocation.toString(), isEx);

            //continue with parser provided by Java. If schema cannot be located, an exception will be thrown
            return null;
        }
    }

    @Override
    public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId,
            String baseURI) {

        InputSource entity;

        try {
            entity = locateEntity(systemId, publicId);
        } catch (IOException e) {
            throw new CmsException(e);
        }

        if (entity == null || entity.getByteStream() == null) {
            return null;
        }

        DOMImplementationLS domImplementationLS = (DOMImplementationLS) registry.getDOMImplementation("LS");

        LSInput lsInput = domImplementationLS.createLSInput();

        lsInput.setByteStream(entity.getByteStream());
        lsInput.setSystemId(systemId);

        return lsInput;
    }
}