in languagetool-server/src/main/java/org/languagetool/server/HTTPServerConfig.java [313:524]
private void parseConfigFile(File file, boolean loadLangModel) {
try {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(file)) {
props.load(fis);
maxTextHardLength = Integer.parseInt(getOptionalProperty(props, "maxTextHardLength", Integer.toString(Integer.MAX_VALUE)));
maxTextLengthAnonymous = maxTextLengthLoggedIn = maxTextLengthPremium = Integer.parseInt(getOptionalProperty(props, "maxTextLength", Integer.toString(Integer.MAX_VALUE)));
maxTextLengthAnonymous = Integer.parseInt(getOptionalProperty(props, "maxTextLengthAnonymous", String.valueOf(maxTextLengthAnonymous)));
maxTextLengthLoggedIn = Integer.parseInt(getOptionalProperty(props, "maxTextLengthLoggedIn", String.valueOf(maxTextLengthLoggedIn)));
maxTextLengthPremium = Integer.parseInt(getOptionalProperty(props, "maxTextLengthPremium", String.valueOf(maxTextLengthPremium)));
maxCheckTimeMillisAnonymous = maxCheckTimeMillisLoggedIn = maxCheckTimeMillisPremium = Integer.parseInt(getOptionalProperty(props, "maxCheckTimeMillis", "-1"));
maxCheckTimeMillisAnonymous = Long.parseLong(getOptionalProperty(props, "maxCheckTimeMillisAnonymous", String.valueOf(maxCheckTimeMillisAnonymous)));
maxCheckTimeMillisLoggedIn = Long.parseLong(getOptionalProperty(props, "maxCheckTimeMillisLoggedIn", String.valueOf(maxCheckTimeMillisLoggedIn)));
maxCheckTimeMillisPremium = Long.parseLong(getOptionalProperty(props, "maxCheckTimeMillisPremium", String.valueOf(maxCheckTimeMillisPremium)));
requestLimit = Integer.parseInt(getOptionalProperty(props, "requestLimit", "0"));
requestLimitInBytes = Integer.parseInt(getOptionalProperty(props, "requestLimitInBytes", "0"));
timeoutRequestLimit = Integer.parseInt(getOptionalProperty(props, "timeoutRequestLimit", "0"));
requestLimitWhitelistUsers = Arrays.asList(getOptionalProperty(props, "requestLimitWhitelistUsers", "").split(",\\s*"));
requestLimitWhitelistLimit = Integer.parseInt(getOptionalProperty(props, "requestLimitWhitelistLimit", "0"));
pipelineCaching = Boolean.parseBoolean(getOptionalProperty(props, "pipelineCaching", "false").trim());
pipelinePrewarming = Boolean.parseBoolean(getOptionalProperty(props, "pipelinePrewarming", "false").trim());
maxPipelinePoolSize = Integer.parseInt(getOptionalProperty(props, "maxPipelinePoolSize", "5"));
pipelineExpireTime = Integer.parseInt(getOptionalProperty(props, "pipelineExpireTimeInSeconds", "10"));
requestLimitPeriodInSeconds = Integer.parseInt(getOptionalProperty(props, "requestLimitPeriodInSeconds", "0"));
ipFingerprintFactor = Integer.parseInt(getOptionalProperty(props, "ipFingerprintFactor", "1"));
trustXForwardForHeader = Boolean.valueOf(getOptionalProperty(props, "trustXForwardForHeader", "false").trim());
maxWorkQueueSize = Integer.parseInt(getOptionalProperty(props, "maxWorkQueueSize", "0"));
if (maxWorkQueueSize < 0) {
throw new IllegalArgumentException("maxWorkQueueSize must be >= 0: " + maxWorkQueueSize);
}
minPort = Integer.parseInt(getOptionalProperty(props, "minPort", "0"));
maxPort = Integer.parseInt(getOptionalProperty(props, "maxPort", "0"));
String url = getOptionalProperty(props, "serverURL", null);
setServerURL(url);
String ruleIdToConfidence = getOptionalProperty(props, "ruleIdToConfidenceFile", null);
if (ruleIdToConfidence != null) {
ruleIdToConfidenceFile = new File(ruleIdToConfidence);
}
String langModel = getOptionalProperty(props, "languageModel", null);
if (langModel != null && loadLangModel) {
setLanguageModelDirectory(langModel);
}
String fasttextModel = getOptionalProperty(props, "fasttextModel", null);
String fasttextBinary = getOptionalProperty(props, "fasttextBinary", null);
if (fasttextBinary != null && fasttextModel != null) {
setFasttextPaths(fasttextModel, fasttextBinary);
}
maxCheckThreads = Integer.parseInt(getOptionalProperty(props, "maxCheckThreads", "10"));
if (maxCheckThreads < 1) {
throw new IllegalArgumentException("Invalid value for maxCheckThreads, must be >= 1: " + maxCheckThreads);
}
// default value 0 = use maxCheckThreads setting (for compatibility)
maxTextCheckerThreads = Integer.parseInt(getOptionalProperty(props, "maxTextCheckerThreads", "0"));
if (maxTextCheckerThreads < 0) {
throw new IllegalArgumentException("Invalid value for maxTextCheckerThreads, must be >= 1: " + maxTextCheckerThreads);
}
textCheckerQueueSize = Integer.parseInt(getOptionalProperty(props, "textCheckerQueueSize", "8"));
if (textCheckerQueueSize < 0) {
throw new IllegalArgumentException("Invalid value for textCheckerQueueSize, must be >= 1: " + textCheckerQueueSize);
}
boolean atdMode = getOptionalProperty(props, "mode", "LanguageTool").equalsIgnoreCase("AfterTheDeadline");
if (atdMode) {
throw new IllegalArgumentException("The AfterTheDeadline mode is not supported anymore in LanguageTool 3.8 or later");
}
String rulesConfigFilePath = getOptionalProperty(props, "rulesFile", null);
if (rulesConfigFilePath != null) {
rulesConfigFile = new File(rulesConfigFilePath);
if (!rulesConfigFile.exists() || !rulesConfigFile.isFile()) {
throw new RuntimeException("Rules Configuration file cannot be found: " + rulesConfigFile);
}
}
String remoteRulesConfigFilePath = getOptionalProperty(props, "remoteRulesFile", null);
if (remoteRulesConfigFilePath != null) {
remoteRulesConfigFile = new File(remoteRulesConfigFilePath);
if (!remoteRulesConfigFile.exists() || !remoteRulesConfigFile.isFile()) {
throw new RuntimeException("Remote rules configuration file cannot be found: " + remoteRulesConfigFile);
}
}
cacheSize = Integer.parseInt(getOptionalProperty(props, "cacheSize", "0"));
if (cacheSize < 0) {
throw new IllegalArgumentException("Invalid value for cacheSize: " + cacheSize + ", use 0 to deactivate cache");
}
if (props.containsKey("cacheTTLSeconds") && !props.containsKey("cacheSize")) {
throw new IllegalArgumentException("Use of cacheTTLSeconds without also setting cacheSize has no effect.");
}
cacheTTLSeconds = Integer.parseInt(getOptionalProperty(props, "cacheTTLSeconds", "300"));
maxErrorsPerWordRate = Float.parseFloat(getOptionalProperty(props, "maxErrorsPerWordRate", "0"));
suggestionsEnabled = Boolean.parseBoolean(getOptionalProperty(props, "suggestionsEnabled", "true"));
maxSpellingSuggestions = Integer.parseInt(getOptionalProperty(props, "maxSpellingSuggestions", "0"));
blockedReferrers = Arrays.asList(getOptionalProperty(props, "blockedReferrers", "").split(",\\s*"));
setTrustedSources(getOptionalProperty(props, "trustedSources", null));
String premiumAlwaysValue = props.getProperty("premiumAlways");
if (premiumAlwaysValue != null) {
premiumAlways = Boolean.parseBoolean(premiumAlwaysValue.trim());
if (premiumAlways) {
System.out.println("*** Running in PREMIUM-ALWAYS mode");
}
}
premiumOnly = Boolean.valueOf(getOptionalProperty(props, "premiumOnly", "false").trim());
if (premiumOnly) {
if (!Premium.isPremiumVersion()) {
throw new IllegalArgumentException("Cannot use premiumOnly=true with non-premium version");
}
System.out.println("*** Running in PREMIUM-ONLY mode");
}
anonymousAccessAllowed = Boolean.valueOf(getOptionalProperty(props, "anonymousAccessAllowed", "true").trim());
if (!anonymousAccessAllowed) {
System.out.println("*** Running in RESTRICTED-ACCESS mode");
}
redisHost = getOptionalProperty(props, "redisHost", null);
redisPort = Integer.parseInt(getOptionalProperty(props, "redisPort", "6379"));
redisDatabase = Integer.parseInt(getOptionalProperty(props, "redisDatabase", "0"));
redisUseSSL = Boolean.valueOf(getOptionalProperty(props, "redisUseSSL", "true").trim());
redisPassword = getOptionalProperty(props, "redisPassword", null);
redisDictTTL = Integer.parseInt(getOptionalProperty(props, "redisDictTTLSeconds", "600"));
redisTimeout = Integer.parseInt(getOptionalProperty(props, "redisTimeoutMilliseconds", "100"));
redisConnectionTimeout = Integer.parseInt(getOptionalProperty(props, "redisConnectionTimeoutMilliseconds", "5000"));
redisCertificate = getOptionalProperty(props, "redisCertificate", null);
redisKey = getOptionalProperty(props, "redisKey", null);
redisKeyPassword = getOptionalProperty(props, "redisKeyPassword", null);
redisUseSentinel = Boolean.parseBoolean(getOptionalProperty(props, "redisUseSentinel", "false").trim());
sentinelHost = getOptionalProperty(props, "sentinelHost", null);
sentinelPort = Integer.parseInt(getOptionalProperty(props, "sentinelPort", "26379"));
sentinelPassword = getOptionalProperty(props, "sentinelPassword", null);
sentinelMasterId = getOptionalProperty(props, "sentinelMasterId", null);
gracefulDatabaseFailure = Boolean.parseBoolean(getOptionalProperty(props, "gracefulDatabaseFailure", "false").trim());
dbDriver = getOptionalProperty(props, "dbDriver", null);
dbUrl = getOptionalProperty(props, "dbUrl", null);
dbUsername = getOptionalProperty(props, "dbUsername", null);
dbPassword = getOptionalProperty(props, "dbPassword", null);
dbTimeoutSeconds = Integer.parseInt(getOptionalProperty(props, "dbTimeoutSeconds", "10"));
dbMaxConnections = Integer.parseInt(getOptionalProperty(props, "dbMaxConnections", "10"));
databaseErrorRateThreshold = Integer.parseInt(getOptionalProperty(props, "dbErrorRateThreshold", "50"));
databaseTimeoutRateThreshold = Integer.parseInt(getOptionalProperty(props, "dbTimeoutRateThreshold", "100"));
databaseDownIntervalSeconds = Integer.parseInt(getOptionalProperty(props, "dbDownIntervalSeconds", "10"));
dbLogging = Boolean.valueOf(getOptionalProperty(props, "dbLogging", "false").trim());
passwortLoginAccessListPath = getOptionalProperty(props, "passwortLoginAccessListPath", "");
prometheusMonitoring = Boolean.valueOf(getOptionalProperty(props, "prometheusMonitoring", "false").trim());
prometheusPort = Integer.parseInt(getOptionalProperty(props, "prometheusPort", "9301"));
skipLoggingRuleMatches = Boolean.valueOf(getOptionalProperty(props, "skipLoggingRuleMatches", "false").trim());
skipLoggingChecks = Boolean.valueOf(getOptionalProperty(props, "skipLoggingChecks", "false").trim());
if (dbLogging && (dbDriver == null || dbUrl == null || dbUsername == null || dbPassword == null)) {
throw new IllegalArgumentException("dbLogging can only be true if dbDriver, dbUrl, dbUsername, and dbPassword are all set");
}
slowRuleLoggingThreshold = Integer.valueOf(getOptionalProperty(props, "slowRuleLoggingThreshold", "-1"));
disabledRuleIds = Arrays.asList(getOptionalProperty(props, "disabledRuleIds", "").split(",\\s*"));
localApiMode = Boolean.parseBoolean(getOptionalProperty(props, "localApiMode", "false"));
motherTongue = getOptionalProperty(props, "motherTongue", "en-US");
String preferredLanguages = getOptionalProperty(props, "preferredLanguages", "").replace(" ", "");
if (!preferredLanguages.equals("")) {
this.preferredLanguages = Arrays.asList(preferredLanguages.split(","));
}
dictLimitUser = Integer.valueOf(getOptionalProperty(props, "dictLimitUser", "0"));
dictLimitTeam = Integer.valueOf(getOptionalProperty(props, "dictLimitTeam", "0"));
styleGuideLimitUser = Integer.valueOf(getOptionalProperty(props, "styleGuideLimitUser", "0"));
styleGuideLimitTeam = Integer.valueOf(getOptionalProperty(props, "styleGuideLimitTeam", "0"));
requestLimitAccessToken = getOptionalProperty(props, "requestLimitAccessToken", null);
jwtSecret = getOptionalProperty(props, "jwtSecret", null);
externalRolloutServiceUrl = getOptionalProperty(props, "externalRolloutServiceUrl", null);
externalRolloutServiceApiKey = getOptionalProperty(props, "externalRolloutServiceApiKey", null);
globalConfig.setGrammalecteServer(getOptionalProperty(props, "grammalecteServer", null));
globalConfig.setGrammalecteUser(getOptionalProperty(props, "grammalecteUser", null));
globalConfig.setGrammalectePassword(getOptionalProperty(props, "grammalectePassword", null));
String beolingusFile = getOptionalProperty(props, "beolingusFile", null);
if (beolingusFile != null) {
if (new File(beolingusFile).exists()) {
globalConfig.setBeolingusFile(new File(beolingusFile));
} else {
throw new IllegalArgumentException("beolingusFile not found: " + beolingusFile);
}
}
String nerUrl = getOptionalProperty(props, "nerUrl", null);
if (nerUrl != null) {
globalConfig.setNERUrl(nerUrl);
logger.info("Using NER service: " + globalConfig.getNerUrl());
}
for (Object o : props.keySet()) {
String key = (String)o;
if (!KNOWN_OPTION_KEYS.contains(key) && !key.matches("lang-[a-z]+-dictPath") && !key.matches("lang-[a-z]+")) {
System.err.println("***** WARNING: ****");
System.err.println("Key '" + key + "' from configuration file '" + file + "' is unknown. Please check the key's spelling (case is significant).");
System.err.println("Known keys: " + KNOWN_OPTION_KEYS);
}
}
addDynamicLanguages(props);
setAbTest(getOptionalProperty(props, "abTest", null));
setAbTestClients(getOptionalProperty(props, "abTestClients", null));
setAbTestRollout(Integer.parseInt(getOptionalProperty(props, "abTestRollout", "100")));
String ngramLangIdentData = getOptionalProperty(props, "ngramLangIdentData", null);
setDefaultThirdPartyAI(Boolean.parseBoolean(getOptionalProperty(props, "defaultThirdPartyAI", "false")));
if (ngramLangIdentData != null) {
File dir = new File(ngramLangIdentData);
if (!dir.exists() || dir.isDirectory()) {
throw new IllegalArgumentException("ngramLangIdentData does not exist or is a directory (needs to be a ZIP file): " + ngramLangIdentData);
}
setNgramLangIdentData(dir);
}
}
} catch (IOException e) {
throw new RuntimeException("Could not load properties from '" + file + "'", e);
}
}