net.sf.sfac.lang.LocalizedStringTracker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sfac-utils Show documentation
Show all versions of sfac-utils Show documentation
This project is the model side of the Swing Framework and Components (SFaC).
If your doing a clean separation between model (or business) and view (or GUI or rendering) parts of your application,
(like in the MVC pattern), then the only classes of SFaC your model can access are in this project.
On the other hand, the classes in sfac-core project are GUI-specific and should not be known by your model.
The newest version!
/*-------------------------------------------------------------------------
Copyright 2009 Olivier Berlanger
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 net.sf.sfac.lang;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.sf.sfac.file.FileUtils;
import net.sf.sfac.utils.Comparison;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Tracker of the LanguageSupportImpl usage.
* This tracker records which strings defined by the LanguageSupportImpl are used and which strings are not defined in the
* LanguageSupportImpl.
*
* @author Olivier Berlanger
*/
public class LocalizedStringTracker {
static Log log = LogFactory.getLog(LocalizedStringTracker.class);
private static final String THIS_PACKAGE_NAME = LocalizedStringTracker.class.getPackage().getName();
/** full name of the file used to write the string tracking report. */
private String reportFileName;
/** Name of the bundle known by the LanguageSupport. */
private String[] bundleNames;
private Map usage = new TreeMap();
public LocalizedStringTracker(String newReportFileName) {
reportFileName = newReportFileName;
}
public void stringDefined(String bundleName, String key, String value) {
StringUsageInfo info = getInfo(key);
info.setStringDefined(bundleName);
}
public void init(String[] managerBundleNames) {
bundleNames = managerBundleNames;
loadAll();
}
public void stringUsed(String bundleName, String key, String value, int nbrParams) {
StringUsageInfo info = getInfo(key);
info.setStringUsed(bundleName, value, nbrParams);
addCallingPoint(info);
}
public void stringNotFound(String key, String defaultValue, int nbrParams) {
StringUsageInfo info = getInfo(key);
info.setStringNotFound(defaultValue, nbrParams);
addCallingPoint(info);
}
private StringUsageInfo getInfo(String key) {
StringUsageInfo info = usage.get(key);
if (info == null) {
info = new StringUsageInfo(key);
usage.put(key, info);
}
return info;
}
public void saveAll() throws IOException {
String defaultBundleName = bundleNames[bundleNames.length - 1];
File fil = new File(reportFileName);
log.info("Save tracked string info in " + fil);
FileUtils.ensureParentDirectoryExists(fil);
BufferedWriter wr = new BufferedWriter(new FileWriter(fil));
wr.write("# Generated properties based on usage of bundle: ");
wr.write(defaultBundleName);
wr.newLine();
wr.newLine();
wr.newLine();
// save keys not found
wr.write("# Keys not found");
wr.newLine();
wr.write("# -------------------------------------------------------");
wr.newLine();
wr.newLine();
for (Iterator iter = usage.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
StringUsageInfo info = usage.get(key);
if (!info.isDefined()) {
wr.write(info.getComment());
wr.newLine();
wr.write(info.getProperty());
wr.newLine();
}
}
// bundle usages
int nbrBundles = bundleNames.length;
for (int i = 0; i < nbrBundles; i++) {
wr.newLine();
wr.newLine();
String bundleName = bundleNames[i];
wr.write("# Usage of bundle: " + bundleName);
wr.newLine();
wr.write("# -------------------------------------------------------");
wr.newLine();
wr.newLine();
for (Iterator iter = usage.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
StringUsageInfo info = usage.get(key);
if (info.usedByBundle(bundleName)) {
wr.write(info.getProperty());
wr.newLine();
}
}
}
wr.close();
}
public void loadAll() {
File fil = new File(reportFileName);
if (fil.exists()) {
try {
log.info("Load tracked string info from " + fil);
BufferedReader br = new BufferedReader(new FileReader(fil));
String line;
while ((line = br.readLine()) != null) {
if (Comparison.isDefined(line)) {
if (line.startsWith("#% ")) {
// reload previous string-not-found info
stringNotFoundReloaded(line);
// skip next line
br.readLine();
} else if (!line.startsWith("#")) {
propertyReloaded(line);
}
}
}
br.close();
} catch (IOException ioe) {
log.error("Failed to load existing tracker info from: " + fil, ioe);
}
} else {
log.info("No existing tracked string info (" + fil + ")");
}
}
private void addCallingPoint(StringUsageInfo info) {
String callingPoint = null;
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
for (StackTraceElement element : stack) {
String className = element.getClassName();
if (!(className.startsWith("java.") || className.startsWith(THIS_PACKAGE_NAME) || className
.startsWith("net.sf.sfac.gui.framework"))) {
callingPoint = element.toString();
break;
}
}
if (callingPoint != null) {
info.addCallingPoint(callingPoint);
}
}
private void stringNotFoundReloaded(String comment) {
String[] tokens = comment.substring(3).split("\\|");
String key = tokens[0];
StringUsageInfo info = getInfo(key);
info.setStringNotFoundReloaded(tokens);
}
private void propertyReloaded(String line) {
int equalIndex = line.indexOf('=');
if (equalIndex > 0) {
String key = line.substring(0, equalIndex);
String value = line.substring(equalIndex + 1);
if (!value.startsWith("NOT USED")) {
StringUsageInfo info = getInfo(key);
info.setStringUsed(value);
}
} else {
log.error("Wrong property line in tracker info: " + line);
}
}
static class StringUsageInfo {
private String[] defBundleNames;
private String key;
private String translation;
private int nbrParams;
private Set callingPoints = new HashSet();
public StringUsageInfo(String newKey) {
key = newKey;
}
public void setStringNotFoundReloaded(String[] tokens) {
// key = tokens[0];
if (log.isDebugEnabled()) log.debug("Parse tokens: " + Arrays.toString(tokens));
translation = tokens[1];
nbrParams = Integer.parseInt(tokens[2]);
for (int i = 3; i < tokens.length; i++) {
callingPoints.add(tokens[i]);
}
}
public void setStringNotFound(String defaultValue, int newNbrParams) {
translation = defaultValue;
nbrParams = newNbrParams;
}
public void setStringDefined(String bundleName) {
if (bundleName == null) throw new IllegalArgumentException("bundleName cannot be null");
if (defBundleNames == null) defBundleNames = new String[] { bundleName };
else if (!usedByBundle(bundleName)) {
int len = defBundleNames.length;
String[] newNames = new String[len + 1];
System.arraycopy(defBundleNames, 0, newNames, 0, len);
newNames[len] = bundleName;
defBundleNames = newNames;
}
}
public boolean isDefined() {
return defBundleNames != null;
}
public boolean usedByBundle(String bundleName) {
int len = (defBundleNames == null) ? 0 : defBundleNames.length;
for (int i = 0; i < len; i++) {
if (defBundleNames[i].equals(bundleName)) return true;
}
return false;
}
public void setStringUsed(String bundleName, String newTranslation, int newNbrParams) {
setStringDefined(bundleName);
translation = newTranslation;
nbrParams = newNbrParams;
}
public void setStringUsed(String newTranslation) {
translation = newTranslation;
}
public void addCallingPoint(String callingPoint) {
callingPoints.add(callingPoint);
}
private String getSingleLineTranslation() {
return (Comparison.isEmpty(translation)) ? "?" : translation.replaceAll("\n", "\\n");
}
public String getComment() {
StringBuffer sb = new StringBuffer();
sb.append("#% ");
sb.append(key);
sb.append('|');
sb.append(getSingleLineTranslation());
sb.append('|');
sb.append(nbrParams);
for (String callingPoint : callingPoints) {
sb.append('|');
sb.append(callingPoint);
}
return sb.toString();
}
public String getProperty() {
String status;
if (defBundleNames == null) status = (translation == null) ? "???" : "?" + translation;
else if (translation == null) status = "NOT USED";
else status = getSingleLineTranslation();
if (nbrParams > 0) status += " [" + nbrParams + "]";
if ((defBundleNames != null) && (defBundleNames.length > 1)) {
status += " DUPLICATE(" + Arrays.toString(defBundleNames) + ")";
}
return key + "=" + status;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy