[New] Added bundle persisting to LogMessage and retrieval scheme
This commit is contained in:
parent
80841770e2
commit
37ac403923
|
@ -76,6 +76,7 @@ public class Tags {
|
||||||
public static final String LOCATOR = "Locator";
|
public static final String LOCATOR = "Locator";
|
||||||
public static final String SEVERITY = "Severity";
|
public static final String SEVERITY = "Severity";
|
||||||
public static final String KEY = "Key";
|
public static final String KEY = "Key";
|
||||||
|
public static final String BUNDLE = "Bundle";
|
||||||
public static final String LOG_MESSAGE = "LogMessage";
|
public static final String LOG_MESSAGE = "LogMessage";
|
||||||
public static final String MESSAGE = "Message";
|
public static final String MESSAGE = "Message";
|
||||||
public static final String EXCEPTION = "Exception";
|
public static final String EXCEPTION = "Exception";
|
||||||
|
@ -133,6 +134,7 @@ public class Tags {
|
||||||
public static final String LOCATOR = "locator";
|
public static final String LOCATOR = "locator";
|
||||||
public static final String SEVERITY = "severity";
|
public static final String SEVERITY = "severity";
|
||||||
public static final String KEY = "key";
|
public static final String KEY = "key";
|
||||||
|
public static final String BUNDLE = "bundle";
|
||||||
public static final String MESSAGE = "message";
|
public static final String MESSAGE = "message";
|
||||||
public static final String MESSAGES = "messages";
|
public static final String MESSAGES = "messages";
|
||||||
public static final String REALM = "realm";
|
public static final String REALM = "realm";
|
||||||
|
|
|
@ -14,6 +14,7 @@ public class I18nMessageJsonParser {
|
||||||
public I18nMessage parse(JsonObject messageJ) {
|
public I18nMessage parse(JsonObject messageJ) {
|
||||||
|
|
||||||
String key = messageJ.get(Tags.Json.KEY).getAsString();
|
String key = messageJ.get(Tags.Json.KEY).getAsString();
|
||||||
|
String bundle = messageJ.get(Tags.Json.BUNDLE).getAsString();
|
||||||
String message = messageJ.get(Tags.Json.MESSAGE).getAsString();
|
String message = messageJ.get(Tags.Json.MESSAGE).getAsString();
|
||||||
|
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
|
@ -29,6 +30,6 @@ public class I18nMessageJsonParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new I18nMessage(key, properties, message);
|
return new I18nMessage(bundle, key, properties, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,9 @@ public class LogMessage extends I18nMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public LogMessage(String id, ZonedDateTime zonedDateTime, String realm, String username, Locator locator,
|
public LogMessage(String id, ZonedDateTime zonedDateTime, String realm, String username, Locator locator,
|
||||||
LogSeverity severity, LogMessageState state, String key, Properties values, String message,
|
LogSeverity severity, LogMessageState state, String bundle, String key, Properties values, String message,
|
||||||
String stackTrace) {
|
String stackTrace) {
|
||||||
super(key, values, message);
|
super(bundle, key, values, message);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.zonedDateTime = zonedDateTime;
|
this.zonedDateTime = zonedDateTime;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
|
@ -153,6 +153,7 @@ public class LogMessage extends I18nMessage {
|
||||||
LogSeverity severity = LogSeverity.valueOf(messageJ.get(Json.SEVERITY).getAsString());
|
LogSeverity severity = LogSeverity.valueOf(messageJ.get(Json.SEVERITY).getAsString());
|
||||||
LogMessageState state = LogMessageState.valueOf(messageJ.get(Json.STATE).getAsString());
|
LogMessageState state = LogMessageState.valueOf(messageJ.get(Json.STATE).getAsString());
|
||||||
String key = messageJ.get(Json.KEY).getAsString();
|
String key = messageJ.get(Json.KEY).getAsString();
|
||||||
|
String bundle = messageJ.get(Json.BUNDLE).getAsString();
|
||||||
String message = messageJ.get(Json.MESSAGE).getAsString();
|
String message = messageJ.get(Json.MESSAGE).getAsString();
|
||||||
String stackTrace = messageJ.has(Json.EXCEPTION) ? messageJ.get(Json.EXCEPTION).getAsString() : "";
|
String stackTrace = messageJ.has(Json.EXCEPTION) ? messageJ.get(Json.EXCEPTION).getAsString() : "";
|
||||||
|
|
||||||
|
@ -164,8 +165,8 @@ public class LogMessage extends I18nMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LogMessage(id, zonedDateTime, realm, username, locator, severity, state, key, properties, message,
|
return new LogMessage(id, zonedDateTime, realm, username, locator, severity, state, bundle, key, properties,
|
||||||
stackTrace);
|
message, stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,12 +26,13 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
private static final String USERNAME = "username";
|
private static final String USERNAME = "username";
|
||||||
private static final String SEVERITY = "severity";
|
private static final String SEVERITY = "severity";
|
||||||
private static final String LOCATOR = "locator";
|
private static final String LOCATOR = "locator";
|
||||||
|
private static final String BUNDLE = "bundle";
|
||||||
private static final String KEY = "key";
|
private static final String KEY = "key";
|
||||||
private static final String MESSAGE = "message";
|
private static final String MESSAGE = "message";
|
||||||
private static final String STACK_TRACE = "stacktrace";
|
private static final String STACK_TRACE = "stacktrace";
|
||||||
private static final String STATE = "state";
|
private static final String STATE = "state";
|
||||||
|
|
||||||
private static final String FIELDS = commaSeparated(ID, REALM, DATE_TIME, USERNAME, SEVERITY, STATE, LOCATOR, KEY,
|
private static final String FIELDS = commaSeparated(ID, REALM, DATE_TIME, USERNAME, SEVERITY, STATE, LOCATOR, BUNDLE, KEY,
|
||||||
MESSAGE, STACK_TRACE);
|
MESSAGE, STACK_TRACE);
|
||||||
|
|
||||||
private static final String queryByRealmMaxSql =
|
private static final String queryByRealmMaxSql =
|
||||||
|
@ -39,7 +40,7 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
private static final String queryValuesSql = "select key, value from operations_log_values where id = ?";
|
private static final String queryValuesSql = "select key, value from operations_log_values where id = ?";
|
||||||
|
|
||||||
private static final String insertLogMessageSql = "insert into operations_log (" + FIELDS
|
private static final String insertLogMessageSql = "insert into operations_log (" + FIELDS
|
||||||
+ ") values (?, ?, ?, ?, ?::log_severity_type, ?::log_state_type, ?, ?, ?, ?)";
|
+ ") values (?, ?, ?, ?, ?::log_severity_type, ?::log_state_type, ?, ?, ?, ?, ?)";
|
||||||
private static final String insertValuesSql = "insert into operations_log_values (id, key, value) values (?, ?, ?)";
|
private static final String insertValuesSql = "insert into operations_log_values (id, key, value) values (?, ?, ?)";
|
||||||
|
|
||||||
private static final String updateLogMessageStateSql = "update operations_log set state = ?::log_state_type where id = ?";
|
private static final String updateLogMessageStateSql = "update operations_log set state = ?::log_state_type where id = ?";
|
||||||
|
@ -281,9 +282,10 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
// 5 severity = ?,
|
// 5 severity = ?,
|
||||||
// 6 state = ?
|
// 6 state = ?
|
||||||
// 7 locator = ?,
|
// 7 locator = ?,
|
||||||
// 8 key = ?,
|
// 8 bundle = ?,
|
||||||
// 9 message = ?,
|
// 9 key = ?,
|
||||||
// 10 stacktrace = ?,
|
// 10 message = ?,
|
||||||
|
// 11 stacktrace = ?,
|
||||||
|
|
||||||
ps.setString(1, logMessage.getId());
|
ps.setString(1, logMessage.getId());
|
||||||
ps.setString(2, logMessage.getRealm());
|
ps.setString(2, logMessage.getRealm());
|
||||||
|
@ -293,9 +295,10 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
ps.setString(5, logMessage.getSeverity().name());
|
ps.setString(5, logMessage.getSeverity().name());
|
||||||
ps.setString(6, logMessage.getState().name());
|
ps.setString(6, logMessage.getState().name());
|
||||||
ps.setString(7, logMessage.getLocator().toString());
|
ps.setString(7, logMessage.getLocator().toString());
|
||||||
ps.setString(8, logMessage.getKey());
|
ps.setString(8, logMessage.getBundle());
|
||||||
ps.setString(9, logMessage.getMessage());
|
ps.setString(9, logMessage.getKey());
|
||||||
ps.setString(10, logMessage.getStackTrace());
|
ps.setString(10, logMessage.getMessage());
|
||||||
|
ps.setString(11, logMessage.getStackTrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LogMessage logMessageFrom(ResultSet resultSet, ResultSet valuesResult) throws SQLException {
|
private LogMessage logMessageFrom(ResultSet resultSet, ResultSet valuesResult) throws SQLException {
|
||||||
|
@ -307,9 +310,10 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
LogSeverity severity = LogSeverity.valueOf(resultSet.getString(5));
|
LogSeverity severity = LogSeverity.valueOf(resultSet.getString(5));
|
||||||
LogMessageState state = LogMessageState.valueOf(resultSet.getString(6));
|
LogMessageState state = LogMessageState.valueOf(resultSet.getString(6));
|
||||||
Locator locator = Locator.valueOf(resultSet.getString(7));
|
Locator locator = Locator.valueOf(resultSet.getString(7));
|
||||||
String key = resultSet.getString(8);
|
String bundle = resultSet.getString(8);
|
||||||
String message = resultSet.getString(9);
|
String key = resultSet.getString(9);
|
||||||
String exception = resultSet.getString(10);
|
String message = resultSet.getString(10);
|
||||||
|
String exception = resultSet.getString(11);
|
||||||
|
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
while (valuesResult.next()) {
|
while (valuesResult.next()) {
|
||||||
|
@ -318,7 +322,7 @@ public class PostgreSqlLogMessageDao implements LogMessageDao {
|
||||||
properties.setProperty(valueK, valueV);
|
properties.setProperty(valueK, valueV);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LogMessage(id, dateTime, realm, username, locator, severity, state, key, properties, message,
|
return new LogMessage(id, dateTime, realm, username, locator, severity, state, bundle, key, properties, message,
|
||||||
exception);
|
exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS resources;
|
||||||
|
DROP TABLE IF EXISTS orders;
|
||||||
|
DROP TABLE IF EXISTS activities;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS audits;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS operations_log;
|
||||||
|
DROP TABLE IF EXISTS operations_log_values;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS db_version;
|
||||||
|
|
||||||
|
DROP TYPE IF EXISTS order_state;
|
||||||
|
DROP TYPE IF EXISTS access_type;
|
||||||
|
DROP TYPE IF EXISTS log_severity_type;
|
||||||
|
DROP TYPE IF EXISTS log_state_type;
|
|
@ -0,0 +1,217 @@
|
||||||
|
|
||||||
|
-- DB_VERSION
|
||||||
|
CREATE TABLE IF NOT EXISTS db_version (
|
||||||
|
id serial primary key not null,
|
||||||
|
app varchar(255) not null,
|
||||||
|
version varchar(255) not null,
|
||||||
|
description varchar(255) not null,
|
||||||
|
created timestamp with time zone not null
|
||||||
|
);
|
||||||
|
|
||||||
|
-- RESOURCES
|
||||||
|
CREATE TABLE IF NOT EXISTS resources (
|
||||||
|
id varchar(255) not null,
|
||||||
|
version integer not null,
|
||||||
|
created_by varchar(255) not null,
|
||||||
|
created_at timestamp with time zone not null,
|
||||||
|
updated_at timestamp with time zone not null,
|
||||||
|
deleted boolean not null,
|
||||||
|
latest boolean not null,
|
||||||
|
name varchar(255) not null,
|
||||||
|
type varchar(255) not null,
|
||||||
|
asxml xml,
|
||||||
|
asjson json,
|
||||||
|
|
||||||
|
PRIMARY KEY (id, version)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ORDERS
|
||||||
|
CREATE TYPE order_state AS ENUM ('CREATED', 'PLANNING', 'PLANNED', 'EXECUTION', 'STOPPED', 'WARNING', 'ERROR', 'EXECUTED', 'CLOSED');
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS orders (
|
||||||
|
id varchar(255) not null,
|
||||||
|
version integer not null,
|
||||||
|
created_by varchar(255) not null,
|
||||||
|
created_at timestamp with time zone not null,
|
||||||
|
updated_at timestamp with time zone not null,
|
||||||
|
deleted boolean,
|
||||||
|
latest boolean not null,
|
||||||
|
name varchar(255),
|
||||||
|
type varchar(255),
|
||||||
|
state order_state,
|
||||||
|
date timestamp with time zone,
|
||||||
|
asxml xml,
|
||||||
|
asjson json,
|
||||||
|
|
||||||
|
PRIMARY KEY (id, version)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ACTIVITIES
|
||||||
|
CREATE TABLE IF NOT EXISTS activities (
|
||||||
|
id varchar(255) not null,
|
||||||
|
version integer not null,
|
||||||
|
created_by varchar(255) not null,
|
||||||
|
created_at timestamp with time zone not null,
|
||||||
|
updated_at timestamp with time zone not null,
|
||||||
|
deleted boolean not null,
|
||||||
|
latest boolean not null,
|
||||||
|
name varchar(255) not null,
|
||||||
|
type varchar(255) not null,
|
||||||
|
state order_state,
|
||||||
|
asxml xml,
|
||||||
|
asjson json,
|
||||||
|
|
||||||
|
PRIMARY KEY (id, version)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AUDITS
|
||||||
|
CREATE TYPE access_type AS ENUM ('READ', 'CREATE', 'UPDATE', 'DELETE');
|
||||||
|
CREATE TABLE IF NOT EXISTS audits (
|
||||||
|
id bigint PRIMARY KEY,
|
||||||
|
username varchar(255) NOT NULL,
|
||||||
|
firstname varchar(255) NOT NULL,
|
||||||
|
lastname varchar(255) NOT NULL,
|
||||||
|
date timestamp with time zone NOT NULL,
|
||||||
|
|
||||||
|
element_type varchar(255) NOT NULL,
|
||||||
|
element_sub_type varchar(255) NOT NULL,
|
||||||
|
element_accessed varchar(255) NOT NULL,
|
||||||
|
new_version timestamp with time zone,
|
||||||
|
|
||||||
|
action varchar(255) NOT NULL,
|
||||||
|
access_type access_type NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Operations Log
|
||||||
|
CREATE TYPE log_severity_type AS ENUM ('Info', 'Notification', 'Warning', 'Error', 'Exception');
|
||||||
|
CREATE TYPE log_state_type AS ENUM ('Active', 'Inactive', 'Information');
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS operations_log (
|
||||||
|
id varchar(255) PRIMARY KEY,
|
||||||
|
realm varchar(255),
|
||||||
|
dateTime timestamp with time zone,
|
||||||
|
username varchar(255),
|
||||||
|
severity log_severity_type,
|
||||||
|
state log_state_type,
|
||||||
|
locator varchar(1024),
|
||||||
|
bundle varchar(255),
|
||||||
|
key varchar(255),
|
||||||
|
message text,
|
||||||
|
stacktrace text
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS operations_log_values (
|
||||||
|
id varchar(255),
|
||||||
|
key varchar(255),
|
||||||
|
value text
|
||||||
|
);
|
||||||
|
|
||||||
|
-- set version
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.1.0',
|
||||||
|
'strolch',
|
||||||
|
'Initial schema version',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.2.0',
|
||||||
|
'strolch',
|
||||||
|
'Added new table for audits',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.2.1',
|
||||||
|
'strolch',
|
||||||
|
'Added new column app to table table version',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.3.0',
|
||||||
|
'strolch',
|
||||||
|
'Added new column element_sub_type to table audits',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.4.0',
|
||||||
|
'strolch',
|
||||||
|
'Added new table activities',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.5.0',
|
||||||
|
'strolch',
|
||||||
|
'Added versioning to root elements',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.5.1',
|
||||||
|
'strolch',
|
||||||
|
'Added state column to activity, and added new states',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.6.0',
|
||||||
|
'strolch',
|
||||||
|
'Added json column to all tables',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.7.0',
|
||||||
|
'strolch',
|
||||||
|
'Added persisting of operations log',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.8.0',
|
||||||
|
'strolch',
|
||||||
|
'Added updated_at column to all tables',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.9.0',
|
||||||
|
'strolch',
|
||||||
|
'Added log_state column to operations_log',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.9.1',
|
||||||
|
'strolch',
|
||||||
|
'Added bundle column to operations_log',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
-- add bundle column
|
||||||
|
ALTER TABLE operations_log ADD COLUMN bundle varchar(255);
|
||||||
|
|
||||||
|
-- set initial values for new columns
|
||||||
|
UPDATE operations_log SET bundle = '' where bundle IS NULL;
|
||||||
|
|
||||||
|
-- make columns not null
|
||||||
|
ALTER TABLE operations_log ALTER COLUMN bundle SET NOT NULL;
|
||||||
|
|
||||||
|
INSERT INTO db_version
|
||||||
|
(version, app, description, created)
|
||||||
|
values(
|
||||||
|
'0.9.1',
|
||||||
|
'strolch',
|
||||||
|
'Added bundle column to operations_log',
|
||||||
|
CURRENT_TIMESTAMP
|
||||||
|
);
|
|
@ -1,2 +1,2 @@
|
||||||
# Property file defining what the currently expected version is supposed to be
|
# Property file defining what the currently expected version is supposed to be
|
||||||
db_version=0.9.0
|
db_version=0.9.1
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class LogMessageSaxReader extends DefaultHandler {
|
||||||
private Locator locator;
|
private Locator locator;
|
||||||
private LogSeverity severity;
|
private LogSeverity severity;
|
||||||
private LogMessageState state;
|
private LogMessageState state;
|
||||||
|
private String bundle;
|
||||||
private String key;
|
private String key;
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
private String message;
|
private String message;
|
||||||
|
@ -103,7 +104,7 @@ public class LogMessageSaxReader extends DefaultHandler {
|
||||||
this.state = LogMessageState.Information;
|
this.state = LogMessageState.Information;
|
||||||
|
|
||||||
LogMessage logMessage = new LogMessage(this.id, this.dateTime, this.realm, this.username, this.locator,
|
LogMessage logMessage = new LogMessage(this.id, this.dateTime, this.realm, this.username, this.locator,
|
||||||
this.severity, this.state, this.key, this.properties, this.message, this.exception);
|
this.severity, this.state, this.bundle, this.key, this.properties, this.message, this.exception);
|
||||||
this.logMessageConsumer.accept(logMessage);
|
this.logMessageConsumer.accept(logMessage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -127,6 +128,11 @@ public class LogMessageSaxReader extends DefaultHandler {
|
||||||
this.sb = null;
|
this.sb = null;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Tags.BUNDLE:
|
||||||
|
this.bundle = this.sb.toString();
|
||||||
|
this.sb = null;
|
||||||
|
break;
|
||||||
|
|
||||||
case Tags.KEY:
|
case Tags.KEY:
|
||||||
this.key = this.sb.toString();
|
this.key = this.sb.toString();
|
||||||
this.sb = null;
|
this.sb = null;
|
||||||
|
|
|
@ -2,11 +2,17 @@ package li.strolch.utils;
|
||||||
|
|
||||||
import static li.strolch.utils.helper.StringHelper.EMPTY;
|
import static li.strolch.utils.helper.StringHelper.EMPTY;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.io.File;
|
||||||
import java.util.MissingResourceException;
|
import java.io.FileInputStream;
|
||||||
import java.util.Properties;
|
import java.io.IOException;
|
||||||
import java.util.ResourceBundle;
|
import java.io.InputStream;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import li.strolch.utils.collections.MapOfMaps;
|
||||||
|
import li.strolch.utils.collections.TypedTuple;
|
||||||
import li.strolch.utils.dbc.DBC;
|
import li.strolch.utils.dbc.DBC;
|
||||||
import li.strolch.utils.helper.StringHelper;
|
import li.strolch.utils.helper.StringHelper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -15,40 +21,50 @@ import org.slf4j.LoggerFactory;
|
||||||
public class I18nMessage {
|
public class I18nMessage {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(I18nMessage.class);
|
private static final Logger logger = LoggerFactory.getLogger(I18nMessage.class);
|
||||||
|
private static MapOfMaps<String, Locale, ResourceBundle> bundleMap;
|
||||||
|
|
||||||
|
private final String bundleName;
|
||||||
private final String key;
|
private final String key;
|
||||||
private final Properties values;
|
private final Properties values;
|
||||||
private final ResourceBundle bundle;
|
private final ResourceBundle bundle;
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
public I18nMessage(ResourceBundle bundle, String key) {
|
public I18nMessage(ResourceBundle bundle, String key) {
|
||||||
DBC.INTERIM.assertNotNull("bundle must be set!", bundle);
|
DBC.INTERIM.assertNotNull("bundle may not be null!", bundle);
|
||||||
DBC.INTERIM.assertNotEmpty("key must be set!", key);
|
DBC.INTERIM.assertNotEmpty("key must be set!", key);
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.values = new Properties();
|
this.values = new Properties();
|
||||||
this.bundle = bundle;
|
this.bundle = bundle;
|
||||||
|
this.bundleName = bundle.getBaseBundleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public I18nMessage(String key, Properties values, String message) {
|
public I18nMessage(String bundle, String key, Properties values, String message) {
|
||||||
|
DBC.INTERIM.assertNotNull("bundle must not be empty!", bundle);
|
||||||
DBC.INTERIM.assertNotEmpty("key must be set!", key);
|
DBC.INTERIM.assertNotEmpty("key must be set!", key);
|
||||||
DBC.INTERIM.assertNotEmpty("message must be set!", message);
|
DBC.INTERIM.assertNotEmpty("message must be set!", message);
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.values = values == null ? new Properties() : values;
|
this.values = values == null ? new Properties() : values;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.bundle = null;
|
this.bundle = findBundle(bundle);
|
||||||
|
this.bundleName = this.bundle == null ? bundle : this.bundle.getBaseBundleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public I18nMessage(I18nMessage i18nMessage) {
|
public I18nMessage(I18nMessage other) {
|
||||||
this.key = i18nMessage.key;
|
this.key = other.key;
|
||||||
this.values = i18nMessage.values;
|
this.values = other.values;
|
||||||
this.bundle = i18nMessage.bundle;
|
this.bundle = other.bundle;
|
||||||
this.message = i18nMessage.message;
|
this.bundleName = other.bundleName;
|
||||||
|
this.message = other.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return this.key;
|
return this.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBundle() {
|
||||||
|
return this.bundle.getBaseBundleName();
|
||||||
|
}
|
||||||
|
|
||||||
public Properties getValues() {
|
public Properties getValues() {
|
||||||
return this.values;
|
return this.values;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +74,8 @@ public class I18nMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceBundle getBundle(Locale locale) {
|
private ResourceBundle getBundle(Locale locale) {
|
||||||
|
if (this.bundle == null)
|
||||||
|
return null;
|
||||||
if (this.bundle.getLocale() == locale)
|
if (this.bundle.getLocale() == locale)
|
||||||
return this.bundle;
|
return this.bundle;
|
||||||
String baseName = this.bundle.getBaseBundleName();
|
String baseName = this.bundle.getBaseBundleName();
|
||||||
|
@ -77,11 +95,22 @@ public class I18nMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage(ResourceBundle bundle) {
|
public String getMessage(ResourceBundle bundle) {
|
||||||
|
DBC.INTERIM.assertNotNull("bundle may not be null!", bundle);
|
||||||
return formatMessage(bundle);
|
return formatMessage(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage(Locale locale) {
|
public String getMessage(Locale locale) {
|
||||||
return formatMessage(getBundle(locale));
|
ResourceBundle bundle = getBundle(locale);
|
||||||
|
if (bundle == null) {
|
||||||
|
logger.warn("No bundle found for " + this.bundleName + " " + locale);
|
||||||
|
logger.info("Available: ");
|
||||||
|
bundleMap.forEach((s, map) -> {
|
||||||
|
logger.info(" " + s);
|
||||||
|
map.forEach((l, resourceBundle) -> logger.info(" " + l + ": " + map.keySet()));
|
||||||
|
});
|
||||||
|
return getMessage();
|
||||||
|
}
|
||||||
|
return formatMessage(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
|
@ -153,4 +182,210 @@ public class I18nMessage {
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceBundle findBundle(String baseName) {
|
||||||
|
if (baseName.isEmpty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (bundleMap == null) {
|
||||||
|
synchronized (I18nMessage.class) {
|
||||||
|
bundleMap = findAllBundles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Locale, ResourceBundle> bundlesByLocale = bundleMap.getMap(baseName);
|
||||||
|
if (bundlesByLocale == null || bundlesByLocale.isEmpty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ResourceBundle bundle = bundlesByLocale.get(Locale.getDefault());
|
||||||
|
if (bundle != null)
|
||||||
|
return bundle;
|
||||||
|
|
||||||
|
return bundlesByLocale.values().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MapOfMaps<String, Locale, ResourceBundle> findAllBundles() {
|
||||||
|
try {
|
||||||
|
CodeSource src = I18nMessage.class.getProtectionDomain().getCodeSource();
|
||||||
|
if (src == null) {
|
||||||
|
logger.error(
|
||||||
|
"Failed to find CodeSource for ProtectionDomain " + I18nMessage.class.getProtectionDomain());
|
||||||
|
return new MapOfMaps<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
File jarLocationF = new File(src.getLocation().toURI());
|
||||||
|
if (!(jarLocationF.exists() && jarLocationF.getParentFile().isDirectory())) {
|
||||||
|
logger.info("Found JAR repository at " + jarLocationF.getParentFile());
|
||||||
|
return new MapOfMaps<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
MapOfMaps<String, Locale, ResourceBundle> bundleMap = new MapOfMaps<>();
|
||||||
|
|
||||||
|
File jarD = jarLocationF.getParentFile();
|
||||||
|
File[] jarFiles = jarD.listFiles((dir, name) -> name.endsWith(".jar"));
|
||||||
|
if (jarFiles == null)
|
||||||
|
return new MapOfMaps<>();
|
||||||
|
|
||||||
|
for (File file : jarFiles) {
|
||||||
|
|
||||||
|
if (shouldIgnoreFile(file))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
logger.info("Scanning JAR " + file.getName() + " for property files...");
|
||||||
|
|
||||||
|
try (JarFile jarFile = new JarFile(file)) {
|
||||||
|
Enumeration<JarEntry> entries = jarFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
JarEntry je = entries.nextElement();
|
||||||
|
|
||||||
|
String entryName = je.getName();
|
||||||
|
|
||||||
|
if (entryName.startsWith("META-INF") //
|
||||||
|
|| entryName.equals("componentVersion.properties") //
|
||||||
|
|| entryName.equals("strolch_db_version.properties"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!entryName.endsWith(".properties"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String propertyName = entryName.replace('/', '.');
|
||||||
|
|
||||||
|
logger.info(" Found property file " + propertyName + " in JAR " + file.getName());
|
||||||
|
|
||||||
|
TypedTuple<String, Locale> tuple = parsePropertyName(entryName);
|
||||||
|
if (tuple == null)
|
||||||
|
continue;
|
||||||
|
String baseName = tuple.getFirst();
|
||||||
|
Locale locale = tuple.getSecond();
|
||||||
|
|
||||||
|
ResourceBundle bundle = ResourceBundle
|
||||||
|
.getBundle(baseName, locale, new CustomControl(jarFile.getInputStream(je)));
|
||||||
|
|
||||||
|
bundleMap.addElement(bundle.getBaseBundleName(), bundle.getLocale(), bundle);
|
||||||
|
logger.info(" Loaded bundle " + bundle.getBaseBundleName() + " " + bundle.getLocale());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File classesD = new File(jarD.getParentFile(), "classes");
|
||||||
|
if (classesD.isDirectory()) {
|
||||||
|
File[] propertyFiles = classesD.listFiles(
|
||||||
|
(dir, name) -> name.endsWith(".properties") && !(name.equals("appVersion.properties") || name
|
||||||
|
.equals("ENV.properties")));
|
||||||
|
if (propertyFiles != null && propertyFiles.length > 0) {
|
||||||
|
for (File propertyFile : propertyFiles) {
|
||||||
|
|
||||||
|
logger.info(" Found property file " + propertyFile.getName() + " in classes " + classesD
|
||||||
|
.getAbsolutePath());
|
||||||
|
|
||||||
|
TypedTuple<String, Locale> tuple = parsePropertyName(propertyFile.getName());
|
||||||
|
if (tuple == null)
|
||||||
|
continue;
|
||||||
|
String baseName = tuple.getFirst();
|
||||||
|
Locale locale = tuple.getSecond();
|
||||||
|
|
||||||
|
ResourceBundle bundle;
|
||||||
|
try (FileInputStream in = new FileInputStream(propertyFile)) {
|
||||||
|
bundle = ResourceBundle.getBundle(baseName, locale, new CustomControl(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
bundleMap.addElement(bundle.getBaseBundleName(), bundle.getLocale(), bundle);
|
||||||
|
logger.info(" Loaded bundle " + bundle.getBaseBundleName() + " " + bundle.getLocale());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Done.");
|
||||||
|
return bundleMap;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to find all property files!", e);
|
||||||
|
return new MapOfMaps<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypedTuple<String, Locale> parsePropertyName(String entryName) {
|
||||||
|
String propertyName = entryName.replace('/', '.');
|
||||||
|
|
||||||
|
String bundleName = propertyName.substring(0, propertyName.lastIndexOf("."));
|
||||||
|
String baseName;
|
||||||
|
Locale locale;
|
||||||
|
int i = bundleName.indexOf('_');
|
||||||
|
if (i > 0) {
|
||||||
|
baseName = bundleName.substring(0, i);
|
||||||
|
String localeS = bundleName.substring(i + 1);
|
||||||
|
String[] parts = localeS.split("_");
|
||||||
|
if (parts.length == 2) {
|
||||||
|
String language = parts[0];
|
||||||
|
String country = parts[1];
|
||||||
|
int languageI = Arrays.binarySearch(Locale.getISOLanguages(), language);
|
||||||
|
int countryI = Arrays.binarySearch(Locale.getISOCountries(), country);
|
||||||
|
if (languageI >= 0 && countryI >= 0)
|
||||||
|
locale = new Locale(language, country);
|
||||||
|
else {
|
||||||
|
logger.warn("Ignoring bad bundle locale for " + entryName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int languageI = Arrays.binarySearch(Locale.getISOLanguages(), localeS);
|
||||||
|
if (languageI >= 0)
|
||||||
|
locale = new Locale(localeS);
|
||||||
|
else {
|
||||||
|
logger.warn("Ignoring bad bundle locale for " + entryName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseName = bundleName;
|
||||||
|
locale = Locale.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TypedTuple<>(baseName, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CustomControl extends ResourceBundle.Control {
|
||||||
|
private final InputStream stream;
|
||||||
|
|
||||||
|
public CustomControl(InputStream stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader,
|
||||||
|
boolean reload) throws IOException {
|
||||||
|
return new PropertyResourceBundle(this.stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldIgnoreFile(File file) {
|
||||||
|
return file.getName().contains("jaxb-core") //
|
||||||
|
|| file.getName().contains("jaxrs-ri") //
|
||||||
|
|| file.getName().contains("jaxb-impl") //
|
||||||
|
|| file.getName().contains("jaxb-api") //
|
||||||
|
|| file.getName().contains("jakarta") //
|
||||||
|
|| file.getName().contains("cron") //
|
||||||
|
|| file.getName().contains("sax") //
|
||||||
|
|| file.getName().contains("aopalliance") //
|
||||||
|
|| file.getName().contains("antlr") //
|
||||||
|
|| file.getName().contains("ST4") //
|
||||||
|
|| file.getName().contains("osgi") //
|
||||||
|
|| file.getName().contains("gson") //
|
||||||
|
|| file.getName().contains("logback") //
|
||||||
|
|| file.getName().contains("slf4j") //
|
||||||
|
|| file.getName().contains("postgresql") //
|
||||||
|
|| file.getName().contains("commons-csv") //
|
||||||
|
|| file.getName().contains("camel") //
|
||||||
|
|| file.getName().contains("yasson") //
|
||||||
|
|| file.getName().contains("tyrus") //
|
||||||
|
|| file.getName().contains("jersey") //
|
||||||
|
|| file.getName().contains("icu4j") //
|
||||||
|
|| file.getName().contains("activation") //
|
||||||
|
|| file.getName().contains("validation-api") //
|
||||||
|
|| file.getName().contains("HikariCP") //
|
||||||
|
|| file.getName().contains("javassist") //
|
||||||
|
|| file.getName().contains("org.abego.treelayout") //
|
||||||
|
|| file.getName().contains("hk2") //
|
||||||
|
|| file.getName().contains("javax") //
|
||||||
|
|| file.getName().contains("grizzly");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue