Skip to content

Commit

Permalink
Merge pull request #79 from jamezp/LOGTOOL-143
Browse files Browse the repository at this point in the history
[LOGTOOL-143] Add the ability to write the index parameter to each fo…
  • Loading branch information
jamezp authored Nov 21, 2019
2 parents 0c12a51 + b04ac84 commit 2599a52
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/processor-options.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ include::expressions.adoc[]
| `skipTranslations` | If set to `true` source files with the translated tet will not be generated. The default is `false`.
| `generatedTranslationFilesPath` | If defined this indicates the path a skeleton file should be generated for the interface. The generated skeleton file will be placed in a directory that matches the package with a name that matches the interface with a `.i18n_locale_COUNTRY_VARIANT.properties` suffix.
| `org.jboss.logging.tools.level` | Sets the maximum level to include in the generated skeleton files. For example if set to `INFO` the skeleton files will not contain any properties where the log level was set to `DEBUG` or `TRACE`.
| `org.jboss.logging.tools.generated.skip.index` | By default when generating a skeleton translation file an index will be appended to the format pattern. For example `Example %s and %d` becomes `Example %1$s and %2$d`. This option allows this behavior to be disabled.

|===

Expand Down
1 change: 1 addition & 0 deletions processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
<test.generated.src.path>${project.build.directory}/generated-test-sources/test-annotations</test.generated.src.path>
<test.report.path>${test.report.path}</test.report.path>
<test.property>sysValue</test.property>
<test.skeleton.file.path>${project.build.testOutputDirectory}</test.skeleton.file.path>
<expressionPropertiesPath>${expression.properties.path}</expressionPropertiesPath>
</systemPropertyVariables>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@
import javax.tools.FileObject;
import javax.tools.StandardLocation;

import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.Transform;
import org.jboss.logging.annotations.Transform.TransformType;
import org.jboss.logging.processor.model.MessageInterface;
import org.jboss.logging.processor.model.MessageMethod;
import org.jboss.logging.processor.model.Parameter;
import org.jboss.logging.processor.validation.StringFormatValidator;

/**
* The generator of skeletal
Expand All @@ -60,7 +62,7 @@
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@SuppressWarnings("MagicNumber")
@SupportedOptions({TranslationFileGenerator.GENERATED_FILES_PATH_OPTION, TranslationFileGenerator.LEVEL_OPTION})
@SupportedOptions({TranslationFileGenerator.GENERATED_FILES_PATH_OPTION, TranslationFileGenerator.LEVEL_OPTION, TranslationFileGenerator.SKIP_INDEX})
final class TranslationFileGenerator extends AbstractGenerator {
private static final Map<String, Integer> levels = new HashMap<>();

Expand All @@ -79,6 +81,8 @@ final class TranslationFileGenerator extends AbstractGenerator {

static final String LEVEL_OPTION = "org.jboss.logging.tools.level";

static final String SKIP_INDEX = "org.jboss.logging.tools.generated.skip.index";

static {

levels.put("ALL", Integer.MIN_VALUE);
Expand All @@ -99,6 +103,7 @@ final class TranslationFileGenerator extends AbstractGenerator {

private final String generatedFilesPath;
private final LevelComparator comparator;
private final boolean skipIndex;

/**
* The constructor.
Expand Down Expand Up @@ -126,6 +131,8 @@ public String run() {
} else {
comparator = null;
}
final String value = options.get(SKIP_INDEX);
this.skipIndex = options.containsKey(SKIP_INDEX) && (value == null || value.isEmpty() || Boolean.parseBoolean(value));
}

@Override
Expand Down Expand Up @@ -290,7 +297,11 @@ private void writeSkeletonMessageMethod(final BufferedWriter writer, final Messa
}
}
writer.write(String.format("%s=", messageMethod.translationKey()));
writer.write(messageMethod.message().value());
if (!skipIndex && messageMethod.message().format() == Message.Format.PRINTF) {
writer.write(addIndexesToFormat(messageMethod));
} else {
writer.write(messageMethod.message().value());
}
writer.newLine();
}

Expand Down Expand Up @@ -352,6 +363,73 @@ private static String getPrimaryClassNamePrefix(final TypeElement element) {
return translationFileName;
}

private String addIndexesToFormat(final MessageMethod method) {
final String format = method.message().value();
int pos = 0;
int i = 0;
final Matcher matcher = StringFormatValidator.PATTERN.matcher(format);
final StringBuilder newFormat = new StringBuilder();
while (i < format.length()) {
if (matcher.find(i)) {
if (matcher.start() != i) {
newFormat.append(format, i, matcher.start());
}
// Pattern should produce 6 groups.
if (matcher.groupCount() != 6) {
logger().warn(method, "Invalid format using \"%s\" for the skeleton value.", format);
return format;
}
// The % is stripped so we need to add it back
newFormat.append('%');
// Initialize the parts so they can be added if they're not null
final String index = matcher.group(1);
final String flags = matcher.group(2);
final String width = matcher.group(3);
final String precision = matcher.group(4);
final String t = matcher.group(5);
final char conversion = matcher.group(6).charAt(0);

if (index == null) {
// If the flags contain < that's a previous index identifier so we should not replace it. Also new
// line (%n) and an escaped percent (%%) do not allow index arguments.
if (flags != null && !flags.contains("<") && conversion != 'n' && conversion != '%') {
newFormat.append(++pos).append('$');
}
} else {
// The index already exists so we'll use that
newFormat.append(index);
}
if (flags != null) {
newFormat.append(flags);
}
if (width != null) {
newFormat.append(width);
}
if (precision != null) {
newFormat.append(precision);
}
if (t != null) {
newFormat.append(t);
}
newFormat.append(conversion);
i = matcher.end();
} else {
// No more formats found, but validate for invalid remaining characters.
newFormat.append(format, i, format.length());
break;
}
}

final String result = newFormat.toString();
// Validate if the changed format is valid and if not fallback to the default format from the message annotation
final StringFormatValidator validator = StringFormatValidator.of(result);
if (!validator.isValid()) {
logger().warn(method, "Could not properly use indexes in the format %s.", format);
return format;
}
return result;
}

private static final class LevelComparator implements Comparable<String> {
private final Integer levelIntValue;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.logging.processor.generated;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Properties;

import org.junit.Assert;
import org.junit.Test;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
public class GeneratedSkeletonTest {

private static final String DIR = System.getProperty("test.skeleton.file.path");

@Test
public void testLoggerIndexes() throws Exception {
final Properties properties = resolveProperties(StringFormatLogger.class);
Assert.assertEquals("String %1$s integer %2$d", properties.getProperty("stringInt"));
Assert.assertEquals("Duke's Birthday: %1$tm %<te,%<tY", properties.getProperty("dukesBirthday"));
Assert.assertEquals("The error is %1$s, I repeat %1$s", properties.getProperty("repeat"));
}

@Test
public void testMessageBundleIndexes() throws Exception {
final Properties properties = resolveProperties(StringFormatMessages.class);
String foundFormat = properties.getProperty("stringInt");
test("String %1$s integer %2$d", foundFormat, "value1", 2);
Assert.assertEquals(StringFormatMessages.MESSAGES.stringInt("value1", 2), String.format(foundFormat, "value1", 2));

foundFormat = properties.getProperty("dukesBirthday");
test("Duke's Birthday: %1$tm %<te,%<tY", foundFormat, new Date());
final Date date = new Date();
Assert.assertEquals(StringFormatMessages.MESSAGES.dukesBirthday(date), String.format(foundFormat, date));

foundFormat = properties.getProperty("repeat");
test("The error is %1$s, I repeat %1$s", foundFormat, "value1");
Assert.assertEquals(StringFormatMessages.MESSAGES.repeat("value1"), String.format(foundFormat, "value1"));

foundFormat = properties.getProperty("twoMixedIndexes");
test("Second %2$s first %1$s", foundFormat, "second", "first");
Assert.assertEquals(StringFormatMessages.MESSAGES.twoMixedIndexes("second", "first"), String.format(foundFormat, "second", "first"));

foundFormat = properties.getProperty("threeMixedIndexes");
test("Third %3$s first %1$s second %2$s", foundFormat, 3, 1, 2);
Assert.assertEquals(StringFormatMessages.MESSAGES.threeMixedIndexes(3, 1, 2), String.format(foundFormat, 3, 1, 2));

foundFormat = properties.getProperty("fourMixedIndexes");
test("Third %3$s first %1$s second %2$s repeat second %2$s", foundFormat, 3, 1, 2);
Assert.assertEquals(StringFormatMessages.MESSAGES.fourMixedIndexes(3, 1, 2), String.format(foundFormat, 3, 1, 2));
}

private void test(final String expectedFormat, final String found, final Object... args) {
Assert.assertEquals(expectedFormat, found);
Assert.assertEquals(String.format(expectedFormat, args), String.format(found, args));
}

private static Properties resolveProperties(final Class<?> type) throws IOException {
final Path file = findFile(type);
final Properties properties = new Properties();
try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
properties.load(reader);
}
return properties;
}
private static Path findFile(final Class<?> type) {
final String filePath = type.getName().replace('.', File.separatorChar) + ".i18n.properties";
Assert.assertNotNull("Could not find the test.skeleton.file.path", DIR);
final Path file = Paths.get(DIR, filePath);
Assert.assertTrue(String.format("File %s was not found.", file), Files.exists(file));
return file;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.logging.processor.generated;

import java.util.Date;

import org.jboss.logging.Messages;
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageBundle;

/**
* @author <a href="mailto:[email protected]">James R. Perkins</a>
*/
@MessageBundle(projectCode = "TEST")
public interface StringFormatMessages {

StringFormatMessages MESSAGES = Messages.getBundle(StringFormatMessages.class);

@Message("String %s integer %d")
String stringInt(String s, int i);

@Message("Duke's Birthday: %1$tm %<te,%<tY")
String dukesBirthday(Date date);

@Message("The error is %s, I repeat %1$s")
String repeat(String message);

@Message("Second %2$s first %s")
String twoMixedIndexes(String second, String first);

@Message("Third %3$s first %s second %s")
String threeMixedIndexes(int third, int first, int second);

@Message("Third %3$s first %s second %2$s repeat second %s")
String fourMixedIndexes(int third, int first, int second);
}

0 comments on commit 2599a52

Please sign in to comment.