Настройка программного обеспечения Java Generate - PullRequest
3 голосов
/ 01 февраля 2012

Я работаю над проектом, в котором есть несколько файлов конфигурации .properties для источника данных, MQ и некоторых других вещей.У нас также есть сценарии запуска оболочки и сценарии профиля пользователя.Проблема, с которой я сталкиваюсь, заключается в том, что мы действительно внедряем это программное обеспечение в 5 различных средах, и, конечно, конфигурация для каждой из них различна.Сложно поддерживать около 30 простых текстовых файлов в конфигурации.Большинство из них почти одинаковы, как и сценарии оболочки, в которых есть только несколько ссылок на пути.

Ребята, знаете ли вы какой-либо инструмент, который я мог бы интегрировать в наш скрипт сборки, который мог бы получить эти свойства из одного файла?или встроенную базу данных, а затем создать правильную конфигурацию среды?Если бы он также мог генерировать сценарии, это было бы еще интереснее.

Спасибо

Ответы [ 4 ]

1 голос
/ 01 февраля 2012

Maven предоставляет это из коробки: http://maven.apache.org/guides/mini/guide-building-for-different-environments.html.

0 голосов
/ 02 февраля 2012

В предыдущем ответе я обрисовал, как Config4 * может удовлетворить ваши потребности.Я решил съесть собственную собачью еду, поэтому я запустил готовое к компиляции и запуску приложение на основе Config4 *, которое будет делать то, что вы хотите.Я предоставляю встроенный код в этом ответе.Вместо того, чтобы читать код через веб-страницу StackOverview, вам может быть проще скопировать и вставить код в файлы, чтобы вы могли просматривать его в текстовом редакторе.

Во-первых, нам нужен файл конфигурации, который определяеттри переменные:

  • deploymentType (указывается в качестве аргумента командной строки для значения dev, staging или prod);

  • files (пары файлов шаблонов и выходных файлов);

  • searchAndReplace (пары строк поиска и замены, применяемые к файлам шаблонов для созданиявыходные файлы).Используемые пары строк зависят от значения deploymentType.

Вот пример такого файла (скопируйте и вставьте его в templates.cfg):

deploymentType ?= ""; # specified with a command-line argument

files = [
    # template file                     output file
    # ----------------------------------------------------
     "log4j-template.properties",       "log4j.properties",
     "hello-template.sh",               "hello.sh",
];

@if (deploymentType == "dev") {
    searchAndReplace = [
        "${db.host}",                   "localhost",
        "${db.user}",                   "guest",
        "${db.log.level}",              "2",
    ];
} @elseIf (deploymentType == "staging") {
    searchAndReplace = [
        "${db.host}",                   exec("hostname"),
        "${db.user}",                   getenv("USERNAME"),
        "${db.log.level}",              "0",
    ];
} @elseIf (deploymentType == "prod") {
    searchAndReplace = [
        "${db.host}",                   "production.example.com",
        "${db.user}",                   getenv("USERNAME"),
        "${db.log.level}",              "0",
    ];
} @else {
    @error "deploymentType must be 'dev', 'staging' or 'prod'";
}

Вот основная строка приложения.Вы должны вырезать и вставить следующую команду в InstantiateTemplateFiles.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.config4j.Configuration;
import org.config4j.SchemaValidator;
import org.config4j.ConfigurationException;

public class InstantiateTemplateFiles
{
    public static void main(String[] args)
    {
        Configuration       cfg = Configuration.create();
        SchemaValidator     sv = new SchemaValidator();
        String[]            searchAndReplace;
        String[]            files;
        String              contents;
        String              modifiedContents;
        String              templateFile;
        String              outputFile;
        int                 i;
        String[]            schema = new String[] {
            "deploymentType = string",
            "searchAndReplace=table[string,search, string,replace]",
            "files=table[string,template-file, string,output-file]",
        };

        if (args.length != 2) {
            System.err.println("\nusage: java InstantiateTemplateFiles"
                    + " meta-config-file.cfg deploymentType\n");
            System.exit(1);
        }
        try {
            //--------
            // Parse the configuration file, perform schema validation
            // and retrieve the required configuration variables.
            //--------
            cfg.insertString("", "deploymentType", args[1]);
            cfg.parse(args[0]);
            sv.parseSchema(schema);
            sv.validate(cfg, "", "");
            searchAndReplace = cfg.lookupList("", "searchAndReplace");
            files = cfg.lookupList("", "files");

            //--------
            // Do the real work
            //--------
            for (i = 0; i < files.length; i += 2) {
                Util.searchAndReplaceInFile(files[i + 0], files[i + 1],
                                            searchAndReplace);
            }
        } catch(IOException ex) {
            System.err.println("\n" + ex.getMessage() + "\n");
            System.exit(1);
        } catch(ConfigurationException ex) {
            System.err.println("\n" + ex.getMessage() + "\n");
            System.exit(1);
        }
    }
}

Наконец, вот код для поиска и замены файлов.Этот код не зависит от Config4 *, поэтому он может оказаться полезным, даже если вы решите создать утилиту, не основанную на Config4 *.Вы должны вырезать и вставить этот код в Util.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Util
{
    public static void searchAndReplaceInFile(
        String      inputFile,
        String      outputFile,
        String[]    searchAndReplacePairs) throws IOException
    {
        String      contents;
        String      modifiedContents;

        contents = Util.readTextFile(inputFile);
        modifiedContents = Util.replace(contents, searchAndReplacePairs);
        Util.writeTextFile(outputFile, modifiedContents);
    }

    public static String readTextFile(String fileName) throws IOException
    {
        BufferedReader          in;
        StringBuffer            result;
        String                  line;

        result = new StringBuffer();
        in = new BufferedReader(new FileReader(fileName));
        while ((line = in.readLine()) != null) {
            result.append(line).append("\n");
        }
        in.close();
        return result.toString();
    }

    public static void writeTextFile(String fileName, String contents)
                                                        throws IOException
    {
        PrintWriter             out;
        StringBuffer            result;
        String                  line;

        out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
        out.print(contents);
        out.close();
    }

    public static String replace(
        String                  origStr,
        String                  searchStr,
        String                  replacementStr)
    {
        StringBuffer            result;
        int                     origStrLen;
        int                     searchStrLen;
        int                     currStart;
        int                     pIndex;

        result = new StringBuffer();
        origStrLen = origStr.length();
        searchStrLen = searchStr.length();
        currStart = 0;
        pIndex = origStr.indexOf(searchStr, currStart);
        while (pIndex != -1) {
            result.append(origStr.substring(currStart, pIndex));
            result.append(replacementStr);
            currStart = pIndex + searchStrLen;
            pIndex = origStr.indexOf(searchStr, currStart);
        }
        result.append(origStr.substring(currStart));
        return result.toString();
    }

    public static String replace(
        String                  origStr,
        String[]                searchAndReplacePairs)
    {
        int                     i;
        int                     currIndex;
        String                  subStr;
        String                  replaceStr;
        StringBuffer            result;
        SearchAndReplacePair[]  pairs;
        SearchAndReplacePair    nextPair;

        pairs = new SearchAndReplacePair[searchAndReplacePairs.length / 2];
        for (i = 0; i < searchAndReplacePairs.length; i += 2) {
            pairs[i/2] = new SearchAndReplacePair(origStr,
                                                  searchAndReplacePairs[i + 0],
                                                  searchAndReplacePairs[i + 1]);
        }

        result = new StringBuffer();
        currIndex = 0;
        nextPair = findNextPair(origStr, currIndex, pairs);
        while (nextPair != null) {
            subStr = origStr.substring(currIndex, nextPair.indexOf);
            result.append(subStr);
            result.append(nextPair.replace);
            currIndex = nextPair.indexOf + nextPair.length;
            for (i = 0; i < pairs.length; i++) {
                pairs[i].findNext(currIndex);
            }
            nextPair = findNextPair(origStr, currIndex, pairs);
        }
        subStr = origStr.substring(currIndex);
        result.append(subStr);

        return result.toString();
    }

    private static SearchAndReplacePair findNextPair(
        String                      origStr,
        int                         currIndex,
        SearchAndReplacePair[]      pairs)
    {
        int                         i;
        SearchAndReplacePair        bestSoFar;
        SearchAndReplacePair        item;

        bestSoFar = null;
        for (i = 0; i < pairs.length; i++) {
            item = pairs[i];
            if (item.indexOf == -1) {
                continue;
            }
            if (bestSoFar == null) {
                bestSoFar = item;
                continue;
            }
            if (bestSoFar.indexOf < item.indexOf) {
                continue;
            }
            if (bestSoFar.indexOf > item.indexOf) {
                bestSoFar = item;
                continue;
            }
            if (bestSoFar.length < item.length) {
                bestSoFar = item;
            }
        }
        return bestSoFar;
    }

}


class SearchAndReplacePair
{
    String      source;
    String      search;
    String      replace;
    int         length;
    int         indexOf;
    int         sourceLength;

    public SearchAndReplacePair(String source, String search, String replace)
    {
        this.source = source;
        this.sourceLength = source.length();
        this.search  = search;
        this.replace = replace;
        this.length  = search.length();
        this.indexOf = source.indexOf(search);
    }


    public void findNext(int fromIndex)
    {
        if (indexOf == -1 || indexOf + 1 == sourceLength) {
            indexOf = -1;
        } else {
            indexOf = source.indexOf(search, fromIndex);
        }
    }

}

Если вы загрузили и установили Config4J (с веб-сайта Config4 *), вы можете скомпилировать утилиту с помощьюследующее:

CLASSPATH=.:/path/to/config4j.jar;
export CLASSPATH
javac -classpath .:/ag/projects/config4j/lib/config4j.jar *.java

Вот пример его запуска:

java InstantiateTemplateFiles templates.cfg prod

Если файл hello-template.sh выглядит так:

#!/bin/sh
DB_HOST=${db.host}
DB_USER=${db.user}
DB_LOG_LEVEL=${db.log.level}
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST

, то сгенерированныйhello.sh файл будет выглядеть так:

#!/bin/sh
DB_HOST=production.example.com
DB_USER=cjmchale
DB_LOG_LEVEL=0
echo Hello from $DB_USER at log level $DB_LOG_LEVEL on host $DB_HOST
0 голосов
/ 02 февраля 2012

Вы можете взглянуть на недавно анонсированную tools4j-config , которая позволяет обрабатывать конфигурацию во время выполнения, а не во время сборки.

0 голосов
/ 02 февраля 2012

Я поддерживаю Config4 *, который является библиотекой синтаксического анализатора файла конфигурации в вариантах C ++ и Java.Большая часть содержимого файла конфигурации Config4 * - это операторы name = value , но вы можете ссылаться на переменные среды и стандартный вывод выполнения некоторых команд, таких как hostname.Вы также можете иметь операторы if-then-else в файле конфигурации.Например (ключевые слова имеют префикс «@»):

@if (exec("hostname") @in ["host1", "host2", "host3"]) {
    ... # set variables to values for production environment
} @elseIf (exec("hostname") @in ["host4", "host5", "host6"]) {
    ... # set variables to values for staging environment
} @else {
    @error "Unknown host";
}

Я называю это настраиваемая конфигурация , поскольку один файл конфигурации может адаптировать свое содержимое для различных хостов, имен пользователей,и так далее.Config4 * предоставляет тривиальный способ интеграции параметров командной строки с файлом конфигурации, поэтому можно иметь файл конфигурации, который адаптирует его содержимое в зависимости от наличия параметра командной строки, такого как -env production или -env staging.Например:

env ?= ""; # set by a command-line option
if (env == "production") {
    ... # set variables to values for production environment
} @elseIf (env == "staging") {
    ... # set variables to values for staging environment
} @else {
    @error "You must specify '-env production' or '-env staging' as a command-line option";
}

Я могу подумать о двух возможных способах, которыми Config4 * мог бы помочь вам.

Один из вариантов для вас - встроить парсер Config4 * в ваши приложения.Тем не менее, хотя я думаю, что это хороший подход при разработке новых приложений, я думаю, что может быть утомительно модернизировать Config4 * для существующего приложения (не потому, что Config4 * сложно использовать, а только потому, что вы будетевносите изменения в существующий код, который использует, скажем, API свойств Java или XML API для использования другого API, и такие модификации, как правило, утомительны).

Второй вариант лучше согласуется со спецификой вашего вопроса.Вы пишете шаблоны версий своих сценариев оболочки и файлов свойств.Эти файлы шаблонов будут использовать определенный синтаксис, такой как '${variable.name}', чтобы указать, где следует использовать значения из файла конфигурации.Затем вы пишете небольшое служебное приложение, которое читает файл шаблона и файл конфигурации, выполняет необходимые замены, а затем записывает преобразованный файл на диск.Вы можете запустить это служебное приложение из вашей системы сборки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...