blob: 10b109a7b03f7edcf43bbcac7c0f2f4c08332fee [file] [log] [blame]
// @java.file.header
/* _________ _____ __________________ _____
* __ ____/___________(_)______ /__ ____/______ ____(_)_______
* _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \
* / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / /
* \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/
*/
package org.gridgain.inspection.abbrev;
import org.jetbrains.annotations.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/**
* Abbreviation rules container.
*
* @author @java.author
* @version @java.version
*/
public class AbbreviationRules {
/** File refresh frequency. */
private static final int FILE_REFRESH_FREQ = 5000;
/** Hardcoded abbreviation table if no abbreviation file can be found. */
private static final String[][] ABBREV_TABLE = {
{"address", "addr"},
{"administration", "admin"},
{"argument", "arg"},
{"array", "arr"},
{"attachment", "attach"},
{"attributes", "attrs"},
{"buffer", "buf"},
{"certificate", "cert"},
{"callable", "call"},
{"char", "c"},
{"channel", "ch"},
{"class", "cls"},
{"closure", "c"},
{"collection", "col"},
{"connection", "conn"},
{"command", "cmd"},
{"communication", "comm"},
{"comparator", "comp"},
{"condition", "cond"},
{"config", "cfg"},
{"context", "ctx"},
{"control", "ctrl"},
{"coordinator", "crd"},
{"copy", "cp"},
{"counter", "cntr"},
{"count", "cnt"},
{"current", "curr"},
{"database", "db"},
{"declare", "decl"},
{"declaration", "decl"},
{"default", "dflt"},
{"delete", "del"},
{"delimiter", "delim"},
{"description", "desc"},
{"descriptor", "descr"},
{"destination", "dest"},
{"directory", "dir"},
{"event", "evt"},
{"exception", "e"},
{"execute", "exec"},
{"expected", "exp"},
{"externalizable", "ext"},
{"frequency", "freq"},
{"future", "fut"},
{"group", "grp"},
{"handler", "hnd"},
{"header", "hdr"},
{"implementation", "impl"},
{"index", "idx"},
{"initial", "init"},
{"initialize", "init"},
{"interface", "itf"},
{"iterator", "iter"},
{"listener", "lsnr"},
{"local", "loc"},
{"locale", "loc"},
{"logger", "log"},
{"loader", "ldr"},
{"manager", "mgr"},
{"message", "msg"},
{"method", "mtd"},
{"microkernel", "mk"},
{"milliseconds", "ms"},
{"multicast", "mcast"},
{"mutex", "mux"},
{"network", "net"},
{"number", "num"},
{"object", "obj"},
{"package", "pkg"},
{"parameter", "param"},
{"permission", "perm"},
{"permissions", "perms"},
{"password", "pwd"},
{"pattern", "ptrn"},
{"policy", "plc"},
{"predicate", "pred"},
{"priority", "pri"},
{"projection", "prj"},
{"projections", "prjs"},
{"property", "prop"},
{"properties", "props"},
{"protocol", "proto"},
{"process", "proc"},
{"query", "qry"},
{"receive", "rcv"},
{"recipient", "rcpt"},
{"reference", "ref"},
{"remove", "rmv"},
{"removed", "rmv"},
{"rename", "ren"},
{"repository", "repo"},
{"request", "req"},
{"resource", "rsrc"},
{"response", "res"},
{"send", "snd"},
{"sender", "snd"},
{"serializable", "ser"},
{"service", "srvc"},
{"session", "ses"},
{"sequence", "seq"},
{"sibling", "sib"},
{"socket", "sock"},
{"source", "src"},
{"specification", "spec"},
{"strategy", "stgy"},
{"string", "str"},
{"system", "sys"},
{"taxonomy", "tax"},
{"timestamp", "ts"},
{"token", "tok"},
{"topology", "top"},
{"unicast", "ucast"},
{"value", "val"},
{"version", "ver"},
{"windows", "win"},
};
/** Map from common words to abbreviations. */
private volatile Map<String, String> abbreviationMap = new ConcurrentHashMap<String, String>();
/** File with abbreviation rules. */
private File abbreviationFile;
/** Initialization latch. */
private CountDownLatch initLatch = new CountDownLatch(1);
/** Singleton instance. */
private static volatile AbbreviationRules instance;
/** Init flag */
private static AtomicBoolean initFlag = new AtomicBoolean();
/** Singleton init latch. */
private static CountDownLatch singletonInitLatch = new CountDownLatch(1);
/**
* Singleton factory.
*
* @param file Abbreviations file.
* @return Instance of abbreviation rules.
*/
public static AbbreviationRules getInstance(@Nullable File file) {
try {
if (initFlag.compareAndSet(false, true)) {
instance = new AbbreviationRules(file);
singletonInitLatch.countDown();
}
else
singletonInitLatch.await();
return instance;
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while waiting for instance initialization");
}
}
/**
* Creates abbreviation rules depending on whether rules file found or not.
*
* @param file Abbreviations file or {@code null} if internal rules should be used.
*/
private AbbreviationRules(File file) {
if (file == null) {
for (String[] entry : ABBREV_TABLE) {
assert entry.length == 2;
abbreviationMap.put(entry[0], entry[1]);
}
initLatch.countDown();
}
else {
abbreviationFile = file;
Thread fileWatchThread = new Thread(new AbbreviationFileWatcher());
fileWatchThread.setDaemon(true);
fileWatchThread.start();
}
}
/**
* Performs lookup of name part in abbreviation table.
*
* @param namePart Name part to lookup.
* @return Abbreviation for given name or {@code null} if there is no such abbreviation.
*/
@Nullable public String getAbbreviation(String namePart) {
try {
if (initLatch.getCount() == 1)
initLatch.await();
return abbreviationMap.get(namePart.toLowerCase());
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* Thread that watches for abbreviation file changes.
*/
private class AbbreviationFileWatcher implements Runnable {
/** File load timestamp. */
private long loadTs;
@Override public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
loadAbbreviations();
if (initLatch.getCount() == 1)
initLatch.countDown();
Thread.sleep(FILE_REFRESH_FREQ);
}
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* Checks for file modification timestamp and refreshes abbreviation rules if needed.
*/
@SuppressWarnings("unchecked")
private void loadAbbreviations() {
if (abbreviationFile.lastModified() > loadTs) {
loadTs = abbreviationFile.lastModified();
InputStream input = null;
try {
input = new FileInputStream(abbreviationFile);
Properties props = new Properties();
props.load(new BufferedReader(new InputStreamReader(input)));
Map<String, String> refreshed = new ConcurrentHashMap<String, String>();
for (Map.Entry<Object, Object> entry : props.entrySet())
refreshed.put((String)entry.getKey(), (String)entry.getValue());
abbreviationMap = refreshed;
}
catch (IOException ignored) {
// Just leave the last state.
}
finally {
if (input != null) {
try {
input.close();
}
catch (IOException ignored) {
}
}
}
}
}
}
}