+
/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Properties;
+import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
* @author gmcarstairs
*
*/
-public class MessageBundleChecker
+public class MessageBundleChecker implements BufferedLineReader.LineCleaner
{
/*
* regex ^"[^"]*"$
private int javaCount;
- private HashSet<String> invalidKeys;
+ private Set<String> invalidKeys;
+
+ private Set<String> dynamicKeys;
/**
* Runs the scan given the path to the root of Java source directories
*/
private void doMain(String srcPath) throws IOException
{
- System.out.println("Scanning " + srcPath
- + " for calls to MessageManager");
+ System.out.println(
+ "Scanning " + srcPath + " for calls to MessageManager\n");
+
sourcePath = srcPath;
loadMessages();
File dir = new File(srcPath);
System.out.println(srcPath + " not found");
return;
}
- invalidKeys = new HashSet<String>();
+
+ invalidKeys = new HashSet<>();
+ dynamicKeys = new HashSet<>();
+
if (dir.isDirectory())
{
scanDirectory(dir);
*/
private void reportResults()
{
- System.out.println("\nScanned " + javaCount + " source files");
- System.out.println("Message.properties has " + messages.size()
- + " keys");
- System.out.println("Found " + invalidKeys.size()
- + " possibly invalid parameter calls");
-
- System.out.println(messageKeys.size()
- + " keys not found, either unused or constructed dynamically");
+ System.out.println(
+ "\nMessages.properties has " + messages.size() + " keys");
+ System.out.println("Scanned " + javaCount + " source files\n");
+
+ if (!invalidKeys.isEmpty())
+ {
+ System.out.println("Found " + invalidKeys.size()
+ + " possibly invalid unmatched key(s) in source code"
+ + (invalidKeys.size() > 1 ? "s" : ""));
+ }
+
+ System.out.println(
+ "Keys not found in source code, assumed constructed dynamically:");
+ int dynamicCount = 0;
for (String key : messageKeys)
{
- System.out.println(" " + key);
+ if (isDynamic(key))
+ {
+ System.out.println(" " + key);
+ dynamicCount++;
+ }
+ }
+
+ if (dynamicCount < messageKeys.size())
+ {
+ System.out.println((messageKeys.size() - dynamicCount)
+ + " key(s) not found, possibly unused, or used indirectly (check code manually!)");
+ for (String key : messageKeys)
+ {
+ if (!isDynamic(key))
+ {
+ System.out.println(" " + key);
+ }
+ }
}
+ System.out
+ .println("\nRun i18nAnt.xml to compare other message bundles");
+ }
+
+ /**
+ * Answers true if the key starts with one of the recorded dynamic key stubs,
+ * else false
+ *
+ * @param key
+ * @return
+ */
+ private boolean isDynamic(String key)
+ {
+ for (String dynamic : dynamicKeys)
+ {
+ if (key.startsWith(dynamic))
+ {
+ return true;
+ }
+ }
+ return false;
}
/**
return;
}
- String[] lines = new String[bufferSize];
BufferedReader br = new BufferedReader(new FileReader(f));
- for (int i = 0; i < bufferSize; i++)
- {
- String readLine = br.readLine();
- lines[i] = stripCommentsAndTrim(readLine);
- }
+ BufferedLineReader blr = new BufferedLineReader(br, bufferSize, this);
int lineNo = 0;
-
- while (lines[bufferSize - 1] != null)
+ String line = blr.read();
+ while (line != null)
{
lineNo++;
- inspectSourceLines(path, lineNo, lines);
-
- for (int i = 0; i < bufferSize - 1; i++)
- {
- lines[i] = lines[i + 1];
- }
- lines[bufferSize - 1] = stripCommentsAndTrim(br.readLine());
+ inspectSourceLines(path, lineNo, line);
+ line = blr.read();
}
br.close();
}
- /*
- * removes anything after (and including) '//'
- */
- private String stripCommentsAndTrim(String line)
- {
- if (line != null)
- {
- int pos = line.indexOf("//");
- if (pos != -1)
- {
- line = line.substring(0, pos);
- }
- line = line.replace("\t", " ").trim();
- }
- return line;
- }
-
/**
* Look for calls to MessageManager methods, possibly split over two or more
- * lines
+ * lines that have been concatenated while parsing the file
*
* @param path
* @param lineNo
- * @param lines
+ * @param line
*/
- private void inspectSourceLines(String path, int lineNo, String[] lines)
+ private void inspectSourceLines(String path, int lineNo,
+ final String line)
{
- String lineNos = String.format("%d-%d", lineNo, lineNo + lines.length
- - 1);
- String combined = combineLines(lines);
+ String lineNos = String.format("%d-%d", lineNo,
+ lineNo + bufferSize - 1);
for (String method : METHODS)
{
- int pos = combined.indexOf(method);
+ int pos = line.indexOf(method);
if (pos == -1)
{
continue;
/*
* extract what follows the opening bracket of the method call
*/
- String methodArgs = combined.substring(pos + method.length()).trim();
+ String methodArgs = line.substring(pos + method.length()).trim();
if ("".equals(methodArgs))
{
/*
continue;
}
+ String messageKey = getMessageKey(method, methodArgs);
+
if (METHOD3 == method)
{
- System.out.println(String.format("Dynamic key at %s line %s %s",
- path.substring(sourcePath.length()), lineNos, combined));
+ String key = messageKey.substring(1, messageKey.length() - 1);
+ if (!dynamicKeys.contains(key))
+ {
+// System.out.println(String.format(
+// "Dynamic key \"" + key + "\" at %s line %s %s",
+// path.substring(sourcePath.length()), lineNos, line));
+ dynamicKeys.add(key);
+ }
continue;
}
- String messageKey = getMessageKey(method, methodArgs);
if (messageKey == null)
{
System.out.println(String.format("Trouble parsing %s line %s %s",
- path.substring(sourcePath.length()), lineNos, combined));
+ path.substring(sourcePath.length()), lineNos, line));
continue;
}
if (!(STRING_PATTERN.matcher(messageKey).matches()))
{
- System.out.println(String.format("Dynamic key at %s line %s %s",
- path.substring(sourcePath.length()), lineNos, combined));
+// System.out.println(String.format("Dynamic key at %s line %s %s",
+// path.substring(sourcePath.length()), lineNos, line));
continue;
}
if (!this.messages.containsKey(messageKey))
{
- System.out.println(String.format(
- "Unmatched key '%s' at line %s of %s", messageKey, lineNos,
- path.substring(sourcePath.length())));
if (!invalidKeys.contains(messageKey))
{
+ // report each key the first time found only
+ System.out.println(String.format(
+ "Unmatched key '%s' at line %s of %s", messageKey,
+ lineNos, path.substring(sourcePath.length())));
invalidKeys.add(messageKey);
}
}
messageKeys.remove(messageKey);
}
+
+ /*
+ * and a brute force scan for _any_ as yet unseen message key, to catch the
+ * cases where it is in a variable or a condition
+ */
+ if (line.contains("\""))
+ {
+ Iterator<String> it = messageKeys.iterator();
+ while (it.hasNext())
+ {
+ if (line.contains(it.next()))
+ {
+ it.remove(); // remove as 'seen'
+ }
+ }
+ }
}
/**
*/
int commaPos = key.indexOf(",");
int bracePos = key.indexOf(")");
- int endPos = commaPos == -1 ? bracePos : (bracePos == -1 ? commaPos
- : Math.min(commaPos, bracePos));
+ int endPos = commaPos == -1 ? bracePos
+ : (bracePos == -1 ? commaPos : Math.min(commaPos, bracePos));
if (endPos == -1 && key.length() > 1 && key.endsWith("\""))
{
endPos = key.length();
return endPos == -1 ? null : key.substring(0, endPos);
}
- private String combineLines(String[] lines)
- {
- String combined = "";
- if (lines != null)
- {
- for (String line : lines)
- {
- if (line != null)
- {
- combined += line;
- }
- }
- }
- return combined;
- }
-
/**
* Loads properties from Message.properties
*
void loadMessages() throws IOException
{
messages = new Properties();
- FileReader reader = new FileReader(new File(sourcePath,
- "../resources/lang/Messages.properties"));
+ FileReader reader = new FileReader(
+ new File(sourcePath, "../resources/lang/Messages.properties"));
messages.load(reader);
reader.close();
- messageKeys = new TreeSet<String>();
+ messageKeys = new TreeSet<>();
for (Object key : messages.keySet())
{
messageKeys.add((String) key);
}
+ /**
+ * Remove any trailing comments, change tabs to space, and trim
+ */
+ @Override
+ public String cleanLine(String l)
+ {
+ if (l != null)
+ {
+ int pos = l.indexOf("//");
+ if (pos != -1)
+ {
+ l = l.substring(0, pos);
+ }
+ l = l.replace("\t", " ").trim();
+ }
+ return l;
+ }
+
}