com.ctriposs.rest4j.tools.idlcheck.Rest4JResourceModelCompatibilityChecker.java Source code

Java tutorial

Introduction

Here is the source code for com.ctriposs.rest4j.tools.idlcheck.Rest4JResourceModelCompatibilityChecker.java

Source

/**
 * Copyright (C) 2014 the original author or authors.
 * See the notice.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * 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.ctriposs.rest4j.tools.idlcheck;

import com.ctriposs.rest4j.tools.compatibility.CompatibilityInfoMap;
import com.ctriposs.rest4j.tools.compatibility.ResourceCompatibilityChecker;
import com.ctriposs.data.schema.DataSchemaResolver;
import com.ctriposs.data.schema.SchemaParserFactory;
import com.ctriposs.data.schema.generator.AbstractGenerator;
import com.ctriposs.data.schema.resolver.DefaultDataSchemaResolver;
import com.ctriposs.data.schema.resolver.XmlFileDataSchemaResolver;
import com.ctriposs.rest4j.restspec.ResourceSchema;
import com.ctriposs.rest4j.restspec.RestSpecCodec;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Stack;

/**
 * Check backwards compatibility between pairs of idl (.restspec.json) files. The check result messages are categorized.
 *
 */
public class Rest4JResourceModelCompatibilityChecker {
    @SuppressWarnings({ "static" })
    public static void main(String[] args) {
        final Options options = new Options();
        options.addOption("h", "help", false, "Print help");
        options.addOption(OptionBuilder.withArgName("compatibility_level").withLongOpt("compat").hasArg()
                .withDescription("Compatibility level " + listCompatLevelOptions()).create('c'));
        final String cmdLineSyntax = Rest4JResourceModelCompatibilityChecker.class.getCanonicalName()
                + " [pairs of <prevRestspecPath currRestspecPath>]";

        final CommandLineParser parser = new PosixParser();
        final CommandLine cmd;

        try {
            cmd = parser.parse(options, args);
        } catch (ParseException e) {
            new HelpFormatter().printHelp(cmdLineSyntax, options, true);
            System.exit(1);
            return; // to suppress IDE warning
        }

        final String[] targets = cmd.getArgs();
        if (cmd.hasOption('h') || targets.length < 2 || targets.length % 2 != 0) {
            new HelpFormatter().printHelp(cmdLineSyntax, options, true);
            System.exit(1);
        }

        final String compatValue;
        if (cmd.hasOption('c')) {
            compatValue = cmd.getOptionValue('c');
        } else {
            compatValue = CompatibilityLevel.DEFAULT.name();
        }

        final CompatibilityLevel compat;
        try {
            compat = CompatibilityLevel.valueOf(compatValue.toUpperCase());
        } catch (IllegalArgumentException e) {
            new HelpFormatter().printHelp(cmdLineSyntax, options, true);
            System.exit(1);
            return;
        }

        final StringBuilder allSummaries = new StringBuilder();
        boolean result = true;
        for (int i = 1; i < targets.length; i += 2) {
            final Rest4JResourceModelCompatibilityChecker checker = new Rest4JResourceModelCompatibilityChecker();
            checker.setResolverPath(System.getProperty(AbstractGenerator.GENERATOR_RESOLVER_PATH));

            String prevTarget = targets[i - 1];
            String currTarget = targets[i];
            result &= checker.check(prevTarget, currTarget, compat);
            allSummaries.append(checker.getInfoMap().createSummary(prevTarget, currTarget));
        }

        if (compat != CompatibilityLevel.OFF && allSummaries.length() > 0) {
            System.out.println(allSummaries);
        }

        System.exit(result ? 0 : 1);
    }

    public void setResolverPath(String resolverPath) {
        _resolverPath = resolverPath;
    }

    /**
     * Check backwards compatibility between two idl (.restspec.json) files.
     *
     * @param prevRestspecPath previously existing idl file
     * @param currRestspecPath current idl file
     * @param compatLevel compatibility level which affects the return value
     * @return true if the check result conforms the compatibility level requirement
     *         e.g. false if backwards compatible changes are found but the level is equivalent
     */
    public boolean check(String prevRestspecPath, String currRestspecPath, CompatibilityLevel compatLevel) {
        _prevRestspecPath = prevRestspecPath;
        _currRestspecPath = currRestspecPath;

        Stack<Object> path = new Stack<Object>();
        path.push("");

        ResourceSchema prevRec = null;
        ResourceSchema currRec = null;

        try {
            prevRec = _codec.readResourceSchema(new FileInputStream(prevRestspecPath));
        } catch (FileNotFoundException e) {
            _infoMap.addRestSpecInfo(CompatibilityInfo.Type.RESOURCE_NEW, path, currRestspecPath);
        } catch (IOException e) {
            _infoMap.addRestSpecInfo(CompatibilityInfo.Type.OTHER_ERROR, path, e.getMessage());
        }

        try {
            currRec = _codec.readResourceSchema(new FileInputStream(currRestspecPath));
        } catch (FileNotFoundException e) {
            _infoMap.addRestSpecInfo(CompatibilityInfo.Type.RESOURCE_MISSING, path, prevRestspecPath);
        } catch (Exception e) {
            _infoMap.addRestSpecInfo(CompatibilityInfo.Type.OTHER_ERROR, path, e.getMessage());
        }

        if (prevRec == null || currRec == null) {
            return _infoMap.isCompatible(compatLevel);
        }

        final DataSchemaResolver resolver;
        if (_resolverPath == null) {
            resolver = new DefaultDataSchemaResolver();
        } else {
            resolver = new XmlFileDataSchemaResolver(SchemaParserFactory.instance(), _resolverPath);
        }

        ResourceCompatibilityChecker checker = new ResourceCompatibilityChecker(prevRec, resolver, currRec,
                resolver);
        boolean check = checker.check(compatLevel);
        _infoMap.addAll(checker.getInfoMap());
        return check;
    }

    /**
     * Check backwards compatibility between two idl (.restspec.json) files.
     *
     * @param prevRestspecPath previously existing idl file
     * @param currRestspecPath current idl file
     * @return true if the previous idl file is equivalent to the current one
     */
    public boolean check(String prevRestspecPath, String currRestspecPath) {
        return check(prevRestspecPath, currRestspecPath, CompatibilityLevel.EQUIVALENT);
    }

    /**
     * @return check results in the backwards incompatibility category.
     *         empty collection if called before checking any files
     */
    @Deprecated
    public Collection<CompatibilityInfo> getIncompatibles() {
        return _infoMap.getIncompatibles();
    }

    /**
     * @return check results in the backwards compatibility category.
     *         empty collection if called before checking any files
     */
    @Deprecated
    public Collection<CompatibilityInfo> getCompatibles() {
        return _infoMap.getCompatibles();
    }

    /**
     * @return summary message about the check result, including all categories
     *         empty string if called before checking any files
     */
    @Deprecated
    public String getSummary() {
        return _infoMap.createSummary(_prevRestspecPath, _currRestspecPath);
    }

    private static String listCompatLevelOptions() {
        final StringBuilder options = new StringBuilder("<");
        for (CompatibilityLevel compatLevel : CompatibilityLevel.values()) {
            options.append(compatLevel.name().toLowerCase()).append("|");
        }
        options.replace(options.length() - 1, options.length(), ">");

        return options.toString();
    }

    public CompatibilityInfoMap getInfoMap() {
        return _infoMap;
    }

    private String _prevRestspecPath;
    private String _currRestspecPath;
    private String _resolverPath;
    private static final RestSpecCodec _codec = new RestSpecCodec();
    private static final Logger log = LoggerFactory.getLogger(Rest4JResourceModelCompatibilityChecker.class);

    private final CompatibilityInfoMap _infoMap = new CompatibilityInfoMap();
}