org.waveprotocol.wave.util.flags.ClientFlagsGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.waveprotocol.wave.util.flags.ClientFlagsGenerator.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.waveprotocol.wave.util.flags;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Generator for FlagConstants.java and ClientFlagsBase.java.
 * 
 * @author dyukon@gmail.com (Denis Konovalchik)
 */
public class ClientFlagsGenerator {

    private static final String FLAG_CONSTANTS_CLASS_NAME = "FlagConstants";
    private static final String CLIENT_FLAGS_CLASS_NAME = "ClientFlags";

    private static final int INDENT_SPACE_COUNT = 2;

    private static final Map<Integer, String> indentsBySize = new HashMap<>();

    private final String defaultConfigFileName;
    private final String generatedPackageName;
    private final String generatedFilesDir;

    private StringBuilder builder;
    private int indentSize;

    public static void main(String[] args) {
        ClientFlagsGenerator generator = new ClientFlagsGenerator(args[0], args[1], args[2]);
        generator.work();
    }

    public ClientFlagsGenerator(String defaultConfigFileName, String generatedPackageName,
            String generatedFilesDir) {
        this.defaultConfigFileName = defaultConfigFileName;
        this.generatedPackageName = generatedPackageName;
        this.generatedFilesDir = generatedFilesDir;
    }

    public void work() {
        List<Parameter> parameters = extractParametersFromDefaultConfigFile(defaultConfigFileName);

        generateFlagConstants(parameters);
        saveToFile(generatedFilesDir + FLAG_CONSTANTS_CLASS_NAME + ".java");

        generateClientFlags(parameters);
        saveToFile(generatedFilesDir + CLIENT_FLAGS_CLASS_NAME + ".java");
    }

    private static List<Parameter> extractParametersFromDefaultConfigFile(String fileName) {
        try {
            List<Parameter> parameters = new ArrayList<>();
            PropertiesConfiguration configuration = new PropertiesConfiguration(fileName);
            Iterator<String> keys = configuration.getKeys();
            while (keys.hasNext()) {
                String key = keys.next();
                parameters.add(Parameter.create(key, configuration.getString(key).trim(),
                        configuration.getLayout().getComment(key)));
            }
            return parameters;
        } catch (ConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    private void generateFlagConstants(List<Parameter> parameters) {
        builder = new StringBuilder();
        indentSize = 0;

        appendDoNotEditWarning();
        appendLine();
        appendPackageName();
        appendLine();
        appendLine("import java.util.HashMap;");
        appendLine("import java.util.Map;");
        appendLine();
        appendClassComment("Contains tags shared between client and server for passing runtime flags.");
        appendClassHeader(FLAG_CONSTANTS_CLASS_NAME);
        appendLine();

        indentSize++;
        int count = 0;
        for (Parameter parameter : parameters) {
            appendLinF("public static final String %s = \"%d\";", parameter.getKey().toUpperCase(), count++);
        }

        appendLine();
        appendLine("private static final Map<String, String> NAME_MAPPING = new HashMap<>();");
        appendLine("static {");
        indentSize++;
        count = 0;
        for (Parameter parameter : parameters) {
            appendLinF("NAME_MAPPING.put(\"%s\", \"%d\");", parameter.getSmallCamelCaseKey(), count++);
        }
        indentSize--;
        appendLine("};");

        appendLine();
        appendLine("public static String getShortName(String name) {");
        appendLine("  return NAME_MAPPING.get(name);");
        appendLine("}");

        indentSize--;
        appendLine("}");
    }

    private void generateClientFlags(List<Parameter> parameters) {
        builder = new StringBuilder();
        indentSize = 0;

        appendDoNotEditWarning();
        appendLine();
        appendPackageName();
        appendLine();
        appendClassComment("Contains definitions, getters and initialization code for flags.");
        appendClassHeader(CLIENT_FLAGS_CLASS_NAME);

        indentSize++;

        for (Parameter parameter : parameters) {
            Enumeration enumeration = parameter.getEnumeration();
            if (enumeration != null) {
                appendLine();
                appendLine("/**");
                appendLinF(" * Enumeration for \"%s\" parameter.", parameter.getSmallCamelCaseKey());
                appendLine(" */");
                appendLinF("public enum %s {", enumeration.getName());

                indentSize++;
                List<String> values = enumeration.getValues();
                int remainCount = values.size();
                for (String value : values) {
                    appendLinF("%s%s", value.toUpperCase(), --remainCount > 0 ? "," : "");
                }
                indentSize--;

                appendLine("}");
            }
        }

        for (Parameter parameter : parameters) {
            appendLine();
            appendLinF("private final %s %s;", parameter.getType(), parameter.getSmallCamelCaseKey());
        }

        appendLine();
        appendLine("/**");
        appendLine(" * Debug information for flag values.");
        appendLine(" *");
        appendLine(" * @return array of pairs (name, value) for each flag.");
        appendLine(" *");
        appendLine(" * WARNING(danilatos): !! This method leaks our flag names. Ensure it is");
        appendLine(" * never called in permutations that can be exposed to the public, so that");
        appendLine(" * it gets compiled out in those cases.");
        appendLine(" */");
        appendLine("public Object[] getDebugPairs() {");

        indentSize++;
        appendLine("return new Object[] {");

        indentSize += 2;
        for (Parameter parameter : parameters) {
            appendLinF("\"%1$s\", %1$s,", parameter.getSmallCamelCaseKey());
        }

        indentSize -= 2;
        appendLine("};");
        indentSize--;
        appendLine("}");

        appendLine();
        appendLine("/**");
        appendLine(" * Constructor which populates fields using ClientFlagsBaseHelper.");
        appendLine(" *");
        appendLine(" * @param helper helper to get parameter values.");
        appendLine(" */");
        appendLinF("public %s(ClientFlagsHelper helper) {", CLIENT_FLAGS_CLASS_NAME);

        indentSize++;
        for (Parameter parameter : parameters) {
            Enumeration enumeration = parameter.getEnumeration();
            if (enumeration != null) {
                appendLinF("%s = %s.valueOf(helper.getString(%s.%s, \"%s\").toUpperCase());",
                        parameter.getSmallCamelCaseKey(), enumeration.getName(), FLAG_CONSTANTS_CLASS_NAME,
                        parameter.getKey().toUpperCase(), parameter.getValue());
            } else {
                appendLinF("%s = helper.get%s(%s.%s, %s);", parameter.getSmallCamelCaseKey(),
                        parameter.getCapitalCaseType(), FLAG_CONSTANTS_CLASS_NAME, parameter.getKey().toUpperCase(),
                        parameter.getValue());
            }
        }
        indentSize--;

        appendLine("}");

        for (Parameter parameter : parameters) {
            appendLine();
            appendGetterComment(parameter.getSmallCamelCaseKey(), parameter.getComment());
            appendLinF("public %s %s() {", parameter.getType(), parameter.getSmallCamelCaseKey());
            appendLinF("  return %s;", parameter.getSmallCamelCaseKey());
            appendLine("}");
        }
        indentSize--;

        appendLine("}");
    }

    private void appendLine() {
        builder.append("\n");
    }

    private void appendLine(String line) {
        builder.append(getIndentBySize(indentSize)).append(line).append("\n");
    }

    private void appendLinF(String format, Object... args) {
        appendLine(String.format(format, args));
    }

    private void appendPackageName() {
        appendLinF("package %s;", generatedPackageName);
    }

    private void appendDoNotEditWarning() {
        appendLine("// ===================================================================");
        appendLine("//");
        appendLine("//   WARNING: GENERATED CODE! DO NOT EDIT!");
        appendLine("//");
        appendLine("// ===================================================================");
        appendLine("//");
        appendLine("// This file is generated");
        appendLine("//");
        appendLine("//   by /src/org/waveprotocol/wave/util/flags/ClientFlagsGenerator.java");
        appendLine("// from /client.default.config");
    }

    private void appendClassComment(String comment) {
        appendLine("/**");
        appendLinF(" * %s", comment);
        appendLine(" */");
    }

    private void appendGetterComment(String field, String comment) {
        appendLine("/**");
        if (comment != null) {
            for (String commentLine : comment.split("\n")) {
                appendLinF(" * %s", commentLine.substring(1).trim());
            }
            appendLine(" *");
        }
        appendLinF(" * @return %s", field);
        appendLine(" */");
    }

    private void appendClassHeader(String className) {
        appendLine("public class " + className + " {");
    }

    private String getIndentBySize(int indentSize) {
        String indent = indentsBySize.get(indentSize);
        if (indent == null) {
            indent = StringUtils.repeat(" ", indentSize * INDENT_SPACE_COUNT);
            indentsBySize.put(indentSize, indent);
        }
        return indent;
    }

    private void saveToFile(String fileName) {
        String text = builder.toString();
        try (PrintWriter printWriter = new PrintWriter(fileName)) {
            printWriter.println(text);
            printWriter.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println(fileName + " has been created.");
    }
}