org.ebayopensource.turmeric.tools.errorlibrary.util.ErrorLibraryUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.ebayopensource.turmeric.tools.errorlibrary.util.ErrorLibraryUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
 * 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
 *******************************************************************************/
package org.ebayopensource.turmeric.tools.errorlibrary.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.io.IOUtils;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.tools.codegen.exception.PreProcessFailedException;
import org.ebayopensource.turmeric.tools.codegen.exception.PreValidationFailedException;
import org.ebayopensource.turmeric.tools.codegen.util.CodeGenUtil;
import org.ebayopensource.turmeric.tools.errorlibrary.ELDomainInfoHolder;
import org.ebayopensource.turmeric.tools.errorlibrary.ErrorLibraryInputOptions;
import org.ebayopensource.turmeric.tools.errorlibrary.ErrorLibraryInputOptions.ErrorLibraryGenType;
import org.ebayopensource.turmeric.tools.errorlibrary.codegen.ErrorLibraryCodeGenContext;
import org.ebayopensource.turmeric.tools.library.utils.TypeLibraryUtilities;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import org.ebayopensource.turmeric.common.config.Error;

public class ErrorLibraryUtils {
    private static final String ERROR_METADATA_PATH = "META-INF/errorlibrary";
    private static final String ERRORBUNDLE_XSD_LOCATION = "META-INF/soa/schema/errorLibrary/ErrorBundle.xsd";
    private static final String PROPERTY_LIST_OF_DOMAINS = "listOfDomains";

    private static Logger s_logger = LogManager.getInstance(ErrorLibraryUtils.class);

    private static Logger getLogger() {
        return s_logger;
    }

    public static boolean validateMetadataFiles(ErrorLibraryCodeGenContext codeGenContext, String domain)
            throws PreProcessFailedException {
        boolean isValidated = false;

        validateAgainstSchema(getXMLLocationForDomain(codeGenContext, domain), ERRORBUNDLE_XSD_LOCATION);
        Set<String> propertiesErrorSet = null;
        Set<String> xmlErrorSet = null;
        StringBuffer duplicatesBuffer = new StringBuffer(400);
        try {
            xmlErrorSet = getUniqueXMLErrorNames(codeGenContext, domain);
        } catch (PreValidationFailedException exception) {
            getLogger().log(Level.FINE, "Duplicates found in ErrorData.xml");
            duplicatesBuffer.append(exception.getMessage());
        }
        try {
            propertiesErrorSet = getUniquePropertyErrorNames(codeGenContext, domain);
        } catch (PreProcessFailedException exception) {
            getLogger().log(Level.FINE, "Duplicates found in Errors.properties");
            duplicatesBuffer.append("\n").append(exception.getMessage());
        }

        try {
            if (xmlErrorSet != null && propertiesErrorSet != null) {
                isConsistent(xmlErrorSet, propertiesErrorSet);
                isValidated = true;
            }
        } catch (PreProcessFailedException exception) {
            getLogger().log(Level.FINE, "Inconsistencies found");
            duplicatesBuffer.append("\n").append(exception.getMessage());
        }

        if (!CodeGenUtil.isEmptyString(duplicatesBuffer.toString()))
            throw new PreProcessFailedException(duplicatesBuffer.toString());

        return isValidated;
    }

    public static boolean isConsistent(Set<String> xmlErrors, Set<String> propertyErrors)
            throws PreProcessFailedException {
        boolean isErrorPropertiesConsistent = false;

        Set<String> propErrorscopy = new HashSet<String>();
        propErrorscopy.addAll(propertyErrors);

        if (propertyErrors.containsAll(xmlErrors)) {
            isErrorPropertiesConsistent = true;
            propErrorscopy.removeAll(xmlErrors);
        }

        if (propErrorscopy.isEmpty())
            getLogger().log(Level.INFO, "The meta-data files are consistent");
        else {
            getLogger().log(Level.WARNING,
                    "The Errors.properties file has more "
                            + "errors defined in addition to those existing in ErrorData.xml. They are \n"
                            + propErrorscopy);
        }
        xmlErrors.removeAll(propertyErrors);

        if (!xmlErrors.isEmpty()) {
            getLogger().log(Level.SEVERE, "The meta-data files are inconsistent. Errors.properties does not"
                    + " have all the errors defined in ErrorData.xml");
            throw new PreProcessFailedException("Errors.properties does not"
                    + " have all the errors defined in ErrorData.xml namely " + xmlErrors);

        }

        return isErrorPropertiesConsistent;
    }

    public static Set<String> getUniquePropertyErrorNames(ErrorLibraryCodeGenContext codeGenContext,
            String domainName) throws PreProcessFailedException {

        List<String> duplicateBuffer = new ArrayList<String>();
        Set<String> propertiesErrorSet = new TreeSet<String>();
        Map<String, String> errorProperties = new HashMap<String, String>();
        InputStream inputStream = null;
        // We don't use java.util.Properties to load the properties. This is because, we wanna figure out 
        // if the entries in the given Error.properties are unique. If we use java.util.Properties, it filters 
        // out the duplicates during loading stage itself and we cannot check for uniqueness.

        BufferedReader propertyReader = null;
        InputStreamReader isr = null;

        try {
            String tempStr = null;
            inputStream = new FileInputStream(new File(getPropertiesLocationForDomain(codeGenContext, domainName)));
            isr = new InputStreamReader(inputStream, "UTF-8");
            propertyReader = new BufferedReader(isr);
            while ((tempStr = propertyReader.readLine()) != null) {
                tempStr = tempStr.trim();
                if (tempStr.contains("=") && !tempStr.startsWith("#")) {
                    String keyValue[] = tempStr.split("=");
                    String key = keyValue[0];
                    String value = null;
                    if (keyValue.length > 1)
                        value = keyValue[1];
                    String existingValue = errorProperties.put(key, value);
                    if (key.endsWith(".message")) {
                        String errorName = key.substring(0, key.lastIndexOf(".message"));
                        if (existingValue != null)
                            duplicateBuffer.add(key.substring(0, key.lastIndexOf(".message")));
                        else
                            propertiesErrorSet.add(errorName);
                    }

                }
            }

        } catch (FileNotFoundException exception) {
            throw new PreProcessFailedException("Properties file not"
                    + " found in the location <errorLibrary>/meta-src/META-INF/errorlibrary/" + domainName,
                    exception);

        } catch (IOException exception) {
            throw new PreProcessFailedException(
                    "IOException in accessing the properties file "
                            + "in the location <errorLibrary>/meta-src/META-INF/errorlibrary/" + domainName,
                    exception);

        } finally {
            CodeGenUtil.closeQuietly(propertyReader);
            CodeGenUtil.closeQuietly(isr);
            CodeGenUtil.closeQuietly(inputStream);
        }

        if (!duplicateBuffer.isEmpty())
            throw new PreValidationFailedException(
                    "Duplicates found in Error.properties. They are " + duplicateBuffer);

        return propertiesErrorSet;
    }

    public static Set<String> getUniqueXMLErrorNames(ErrorLibraryCodeGenContext codeGenContext, String domain)
            throws PreProcessFailedException {

        ELDomainInfoHolder holder = codeGenContext.getDomainInfoMap().get(domain);

        List<String> duplicateBuffer = new ArrayList<String>();
        Set<String> xmlErrorSet = new TreeSet<String>();
        List<String> invalidXMLErrorList = new ArrayList<String>();
        List<Error> errorsInXML = null;
        if (holder.getErrorBundle() != null && holder.getErrorBundle().getErrorlist() != null)
            errorsInXML = holder.getErrorBundle().getErrorlist().getError();

        if (errorsInXML != null) {
            for (Error error : errorsInXML) {
                if (error != null) {
                    if (error.getName() != null && validateVariableSemantics(error.getName())) {
                        boolean entryAdded = xmlErrorSet.add(error.getName());
                        if (!entryAdded)
                            duplicateBuffer.add(error.getName());
                    } else
                        invalidXMLErrorList.add(error.getName());
                }
            }
        }

        if (!invalidXMLErrorList.isEmpty()) {
            throw new PreProcessFailedException("The error name(s) " + invalidXMLErrorList
                    + " have whitespace character and CodeGen cannot proceed. "
                    + "Pls check your ErrorData.xml file and fix it."
                    + " \nAlso check Errors.properties as they have one-one mapping" + " with ErrorData.xml file");

        }

        if (!duplicateBuffer.isEmpty())
            throw new PreValidationFailedException(
                    "Duplicates found in ErrorData.xml. They are " + duplicateBuffer);

        return xmlErrorSet;
    }

    public static boolean validateVariableSemantics(String argument) {

        //TODO  use regular expression instead to check for both upper and lower case alphabets
        boolean isValidate = true;
        if (argument != null)
            for (int i = 0; i < argument.length(); i++)
                if (Character.isWhitespace(argument.charAt(i)) || Character.isSpaceChar(argument.charAt(i))) {
                    isValidate = false;
                    break;
                }
        return isValidate;
    }

    public static boolean validateAgainstSchema(String xmlLocation, String xsdLocation)
            throws PreProcessFailedException {
        boolean isValidate = false;

        Document document = null;
        Schema schema = null;
        try {
            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
            domFactory.setNamespaceAware(true);
            DocumentBuilder parser = domFactory.newDocumentBuilder();
            document = parser.parse(new File(xmlLocation));

            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            URL schemaUrl = Thread.currentThread().getContextClassLoader().getResource(xsdLocation);
            if (schemaUrl == null) {
                throw new PreProcessFailedException("Unable to find schema resource: " + xsdLocation);
            }

            InputStream stream = null;
            try {
                stream = schemaUrl.openStream();
                Source schemaFile = new StreamSource(stream);
                schema = factory.newSchema(schemaFile);
            } finally {
                IOUtils.closeQuietly(stream);
            }

        } catch (ParserConfigurationException exception) {
            throw new PreProcessFailedException("XML parsing failed : " + exception.getMessage(), exception);

        } catch (SAXException exception) {
            throw new PreProcessFailedException("XML parsing failed : " + exception.getMessage(), exception);

        } catch (IOException exception) {
            throw new PreProcessFailedException(
                    "XML parsing failed because of IOException : " + exception.getMessage(), exception);
        } catch (Exception exception) {
            throw new PreProcessFailedException("XML parsing failed : " + exception.getMessage(), exception);
        }

        Validator validator = schema.newValidator();

        try {
            validator.validate(new DOMSource(document));
            isValidate = true;
        } catch (SAXException exception) {
            throw new PreProcessFailedException("XML validation against XSD failed : " + exception.getMessage(),
                    exception);
        } catch (IOException exception) {
            throw new PreProcessFailedException(
                    "Schema validation failed because of IOException : " + exception.getMessage(), exception);
        }

        return isValidate;
    }

    public static String getFullyQualifiedClassName(String packageName, String className)
            throws PreProcessFailedException {

        StringBuffer fullyQualifiedName = new StringBuffer(200);
        if (CodeGenUtil.isEmptyString(className))
            throw new PreProcessFailedException("ClassName cannot be null/empty");
        if (!CodeGenUtil.isEmptyString(packageName) && !CodeGenUtil.isEmptyString(className))
            fullyQualifiedName.append(packageName.toLowerCase()).append(".").append(className);
        return fullyQualifiedName.toString();
    }

    public static String getXMLLocationForDomain(ErrorLibraryCodeGenContext codeGenContext, String domain) {
        StringBuilder xmlLocation = new StringBuilder();
        xmlLocation.append(codeGenContext.getMetaSrcFolder());
        xmlLocation.append(ERROR_METADATA_PATH).append("/");
        xmlLocation.append(domain);
        return CodeGenUtil.toOSFilePath(xmlLocation.toString()) + "ErrorData.xml";
    }

    public static String getPropertiesLocationForDomain(ErrorLibraryCodeGenContext codeGenContext, String domain)
            throws IOException {
        StringBuilder propLocation = new StringBuilder();
        propLocation.append(codeGenContext.getMetaSrcFolder());
        propLocation.append(ERROR_METADATA_PATH).append("/");
        propLocation.append(domain).append("/");

        String propBaseDir = CodeGenUtil.toOSFilePath(propLocation.toString());

        try {
            String[] listOfFiles = TypeLibraryUtilities.getFilesInDir(propBaseDir, ".properties");
            for (String fileName : listOfFiles) {
                if (fileName.startsWith("Errors_en")) {
                    propLocation.append(fileName);
                    break;
                }
            }
        } catch (Exception exception) {
            throw new IOException(exception);
        }
        return propLocation.toString();
    }

    public static List<String> getListOfDomains(String propertyValue) {

        String[] arrayOFDomains = propertyValue.split(",");
        List<String> listOfDomains = new ArrayList<String>();

        for (String currDomain : arrayOFDomains)
            listOfDomains.add(currDomain.trim());

        return listOfDomains;
    }

    public static String readDomainListFromErrorLibraryProperties(ErrorLibraryCodeGenContext codeGenContext)
            throws PreProcessFailedException {
        StringBuilder filename = new StringBuilder();
        filename.append(codeGenContext.getMetaSrcFolder());
        filename.append(ERROR_METADATA_PATH).append("/");
        filename.append(codeGenContext.getInputOptions().getErrorLibraryName());
        filename.append("/domain_list.properties");

        Properties errorLibraryProperties = new Properties();

        File propertiesFile = new File(CodeGenUtil.toOSFilePath(filename.toString()));
        InputStream inStream = null;

        try {
            inStream = new FileInputStream(propertiesFile);
            errorLibraryProperties.load(inStream);
        } catch (FileNotFoundException exception) {
            throw new PreProcessFailedException(
                    "The domain_list.properties file not found. " + exception.getMessage(), exception);
        } catch (IOException exception) {
            throw new PreProcessFailedException(
                    "The domain_list.properties file could not be read due to IOException and"
                            + " hence CodeGen cannot proceed with generation of artifacts. "
                            + exception.getMessage(),
                    exception);
        } finally {
            IOUtils.closeQuietly(inStream);
        }
        return errorLibraryProperties.getProperty(PROPERTY_LIST_OF_DOMAINS);
    }

    public static boolean isGenTypeErrorLibrary(ErrorLibraryInputOptions errorLibraryInputOptions) {
        boolean isErrorLibrary = false;
        if (errorLibraryInputOptions != null)
            if (errorLibraryInputOptions.getCodeGenType() == ErrorLibraryGenType.genTypeDataCollection
                    || errorLibraryInputOptions.getCodeGenType() == ErrorLibraryGenType.genTypeConstants
                    || errorLibraryInputOptions.getCodeGenType() == ErrorLibraryGenType.genTypeErrorLibAll
                    || errorLibraryInputOptions.getCodeGenType() == ErrorLibraryGenType.genTypeCommandLineAll) {

                isErrorLibrary = true;
            }

        return isErrorLibrary;

    }

}