Compare commits

..

No commits in common. 'feature-db-basic' and 'master' have entirely different histories.

  1. 9
      .gitignore
  2. 79
      .idea/workspace.xml
  3. 51
      pom.xml
  4. 86
      src/main/java/org/leolo/nrdatad/App.java
  5. 127
      src/main/java/org/leolo/nrdatad/ConfigurationManager.java
  6. 18
      src/main/java/org/leolo/nrdatad/db/BaseDao.java
  7. 16
      src/main/java/org/leolo/nrdatad/db/DatabaseManager.java
  8. 42
      src/main/java/org/leolo/nrdatad/db/MetadataDao.java
  9. 66
      src/main/java/org/leolo/nrdatad/db/mariadb/DatabaseManager.java
  10. 116
      src/main/java/org/leolo/nrdatad/db/mariadb/MetadataDao.java
  11. 22
      src/main/resources/log4j2.xml
  12. 5
      src/test/java/org/leolo/AppTest.java
  13. 92
      src/test/java/org/leolo/nrdatad/ConfigurationTest.java
  14. 28
      src/test/java/org/leolo/nrdatad/db/test/DatabaseManager.java
  15. 40
      src/test/java/org/leolo/nrdatad/db/test/MetadataDao.java

9
.gitignore vendored

@ -35,11 +35,4 @@ build/
.vscode/
### Mac OS ###
.DS_Store
### Configuration file
/nrdatad.conf
ri_log*
test-*.tmp
.idea/workspace.xml
.idea/
.DS_Store

79
.idea/workspace.xml

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="b9554e7b-3332-419c-960c-8bfbee0d5311" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/aws.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/org/leolo/nrdatad/App.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/test/java/org/leolo/AppTest.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="2GCtKiOdhwqUrJrlolmjYzZXLwa" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="flattenPackages" value="true" />
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false"
}
}]]></component>
<component name="RunManager">
<configuration name="Main" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.leolo.nrdatad.App" />
<module name="nr-data-damon" />
<extension name="software.aws.toolkits.jetbrains.core.execution.JavaAwsConnectionExtension">
<option name="credential" />
<option name="region" />
<option name="useCurrentConnection" value="false" />
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="b9554e7b-3332-419c-960c-8bfbee0d5311" name="Changes" comment="" />
<created>1665904334835</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1665904334835</updated>
<workItem from="1665904336661" duration="319000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
</project>

51
pom.xml

@ -14,8 +14,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
@ -25,42 +25,6 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@ -107,16 +71,5 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

86
src/main/java/org/leolo/nrdatad/App.java

@ -1,95 +1,11 @@
package org.leolo.nrdatad;
import org.apache.commons.cli.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.db.DatabaseManager;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* Hello world!
*
*/
public class App {
Logger log = LogManager.getLogger();
private ConfigurationManager config = ConfigurationManager.getInstance();
public static void main( String[] args ) {
Option confFile = Option.builder()
.required(false)
.hasArg(true)
.argName("fileName")
.option("c")
.longOpt("config-file")
.build();
Options opts = new Options();
opts.addOption(confFile);
String confPath = "nrdatad.conf";
try {
CommandLine cli = new DefaultParser().parse(opts, args);
if(cli.hasOption(confFile)){
confPath = cli.getOptionValue(confFile);
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
new App().run(confPath);
}
private void run(String configPath){
log.always().log("System Started.");
try {
config.loadConfiguration(configPath);
} catch (IOException e) {
log.atError().withThrowable(e).log("Unable to load confog file");
return;
}
// log.atDebug()
if(config.getProperty("general.debug","false").equals("true")){
for(String key:config.stringPropertyNames()){
if(key.endsWith("pwd")){
log.atDebug().log("Config: {} : ****({} chars)", key, config.getProperty(key).length());
}else{
log.atDebug().log("Config: {} : {}", key, config.getProperty(key));
}
}
}
String databaseManagerClass = config.getProperty("db.manager","org.leolo.nrdatad.db.DatabaseManager");
log.atInfo().log("Creating database manager {}", databaseManagerClass);
try {
config.setDatabaseManager((DatabaseManager) Class.forName(databaseManagerClass).getConstructor().newInstance());
} catch (
InstantiationException|IllegalAccessException|InvocationTargetException|
NoSuchMethodException|ClassNotFoundException e
) {
log.atFatal().log("Unable to create instance of {}", databaseManagerClass);
System.exit(1);
return;
} catch (ClassCastException e){
log.atFatal().log("{} is not a DatabaseManager", databaseManagerClass);
System.exit(1);
return;
}
config.getDatabaseManager().initPool();
if(config.getDatabaseManager().checkConnection())
log.atInfo().log("Database connected!");
else{
log.atFatal().log("Unable to connect to database.");
System.exit(1);
return;
}
loadCronJob();
}
private void loadCronJob() {
log.atDebug().log("Start loading cron jobs");
System.out.println( "Hello World!" );
}
}

127
src/main/java/org/leolo/nrdatad/ConfigurationManager.java

@ -1,127 +0,0 @@
package org.leolo.nrdatad;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.db.DatabaseManager;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.*;
import java.util.function.BiConsumer;
public final class ConfigurationManager {
private static ConfigurationManager instance;
Logger logger = LogManager.getLogger();
Properties prop = new Properties();
private DatabaseManager databaseManager;
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
public void setDatabaseManager(DatabaseManager databaseManager) {
this.databaseManager = databaseManager;
}
public synchronized static ConfigurationManager getInstance(){
if(instance==null){
instance = new ConfigurationManager();
}
return instance;
}
private ConfigurationManager(){
}
public void loadConfiguration(String configPath) throws IOException{
logger.atInfo().log("Loading configuration file {}.", configPath);
try(FileReader reader = new FileReader(configPath)) {
prop.load(reader);
}
logger.atInfo().log("Loaded {} setting(s)", prop.size());
}
public Object setProperty(String key, String value) {
return prop.setProperty(key, value);
}
public String getProperty(String key) {
return prop.getProperty(key);
}
public String getProperty(String key, String defaultValue) {
return prop.getProperty(key, defaultValue);
}
public Enumeration<?> propertyNames() {
return prop.propertyNames();
}
public Set<String> stringPropertyNames() {
return prop.stringPropertyNames();
}
public void list(PrintStream out) {
prop.list(out);
}
public void list(PrintWriter out) {
prop.list(out);
}
public int size() {
return prop.size();
}
public boolean isEmpty() {
return prop.isEmpty();
}
public Enumeration<Object> keys() {
return prop.keys();
}
public Enumeration<Object> elements() {
return prop.elements();
}
public boolean contains(Object value) {
return prop.contains(value);
}
public boolean containsValue(Object value) {
return prop.containsValue(value);
}
public boolean containsKey(Object key) {
return prop.containsKey(key);
}
public Set<Object> keySet() {
return prop.keySet();
}
public Collection<Object> values() {
return prop.values();
}
public Set<Map.Entry<Object, Object>> entrySet() {
return prop.entrySet();
}
protected void clear(){
prop.clear();
}
public Object getOrDefault(Object key, Object defaultValue) {
return prop.getOrDefault(key, defaultValue);
}
public void forEach(BiConsumer<? super Object, ? super Object> action) {
prop.forEach(action);
}
}

18
src/main/java/org/leolo/nrdatad/db/BaseDao.java

@ -1,18 +0,0 @@
package org.leolo.nrdatad.db;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class BaseDao {
private DatabaseManager manager;
public BaseDao(DatabaseManager manager){
this.manager = manager;
}
protected Connection getConnection() throws SQLException{
return manager.getConnection();
}
}

16
src/main/java/org/leolo/nrdatad/db/DatabaseManager.java

@ -1,16 +0,0 @@
package org.leolo.nrdatad.db;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.function.BiConsumer;
public interface DatabaseManager {
public void initPool();
public boolean checkConnection();
public Connection getConnection() throws SQLException;
public MetadataDao getMetadataDao();
}

42
src/main/java/org/leolo/nrdatad/db/MetadataDao.java

@ -1,42 +0,0 @@
package org.leolo.nrdatad.db;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.leolo.nrdatad.ConfigurationManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Set;
import java.util.function.BiConsumer;
public abstract class MetadataDao extends BaseDao {
Logger log = LogManager.getLogger();
public MetadataDao(DatabaseManager manager){
super(manager);
}
public abstract String getMetadata(String key, String defaultValue) throws SQLException;
public String getMetadata(String key) throws SQLException{
return getMetadata(key, null);
}
public abstract void updateMetadata(String key, @NotNull String value) throws SQLException;
public abstract Set<String> getKeys() throws SQLException;
public abstract void forEach(BiConsumer<String, String> action) throws SQLException;
public boolean containsKey(String key) throws SQLException{
return getKeys().contains(key);
}
public int entryCount() throws SQLException{
return getKeys().size();
}
}

66
src/main/java/org/leolo/nrdatad/db/mariadb/DatabaseManager.java

@ -1,66 +0,0 @@
package org.leolo.nrdatad.db.mariadb;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.leolo.nrdatad.ConfigurationManager;
import org.leolo.nrdatad.db.MetadataDao;
import org.mariadb.jdbc.MariaDbPoolDataSource;
import java.sql.*;
public class DatabaseManager implements org.leolo.nrdatad.db.DatabaseManager{
Logger logger = LogManager.getLogger();
private MariaDbPoolDataSource ds;
@Override
public void initPool() {
logger.atDebug().log("Start initialize the database pool");
ConfigurationManager conf = ConfigurationManager.getInstance();
if(
!conf.containsKey("db.host")||
!conf.containsKey("db.user")||
!conf.containsKey("db.pwd")||
!conf.containsKey("db.name")
) {
logger.atFatal().log("Missing required property");
System.exit(1);
return;
}
String url = "jdbc:mariadb://"+conf.getProperty("db.host")+
":"+conf.getProperty("db.port", "3306")+
"/"+conf.getProperty("db.name");
logger.atDebug().log("URL={}",url);
try {
ds = new MariaDbPoolDataSource(url);
ds.setMinPoolSize(1);
ds.setMaxPoolSize(Integer.parseInt(conf.getOrDefault("db.poolsize", "20").toString()));
ds.setUser(conf.getProperty("db.user").toString());
ds.setPassword(conf.getProperty("db.pwd").toString());
} catch (SQLException e) {
logger.atFatal().withThrowable(e).log("Cannot connect to DB");
System.exit(-2);
}
}
@Override
public boolean checkConnection() {
try(
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1")
){
return rs.next();
}catch(SQLException e){
return false;
}
}
@Override
public Connection getConnection() throws SQLException{
return ds.getConnection();
}
@Override
public MetadataDao getMetadataDao() {
return new org.leolo.nrdatad.db.mariadb.MetadataDao(this);
}
}

116
src/main/java/org/leolo/nrdatad/db/mariadb/MetadataDao.java

@ -1,116 +0,0 @@
package org.leolo.nrdatad.db.mariadb;
import org.jetbrains.annotations.NotNull;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class MetadataDao extends org.leolo.nrdatad.db.MetadataDao {
private static Object SYNC_TOKEN = new Object();
public MetadataDao(DatabaseManager manager){
super(manager);
}
@Override
public String getMetadata(String key, String defaultValue) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT value FROM metadata WHERE `key` = ?")
){
pstmt.setString(1, key);
try(ResultSet rs = pstmt.executeQuery()){
if(rs.next()){
return rs.getString(1);
}
}
}
return defaultValue;
}
@Override
public void updateMetadata(@NotNull String key, @NotNull String value) throws SQLException {
synchronized (SYNC_TOKEN) {
if (containsKey(key)) {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("UPDATE metadata SET value = ? WHERE `key` = ?")
){
pstmt.setString(1, value);
pstmt.setString(2, key);
pstmt.executeUpdate();
}
} else {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO metadata (`key`, value) VALUES (?,?)")
){
pstmt.setString(1, key);
pstmt.setString(2, value);
pstmt.executeUpdate();
}
}
}
}
@Override
public Set<String> getKeys() throws SQLException {
HashSet<String> set = new HashSet<>();
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT `key` FROM metadata")
){
while(rs.next()){
set.add(rs.getString(1));
}
}
return set;
}
@Override
public void forEach(BiConsumer<String, String> action) throws SQLException {
TreeMap<String, String> map = new TreeMap<>();
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT `key`, value FROM metadata")
){
while(rs.next()){
map.put(rs.getString(1), rs.getString(2));
}
}
map.forEach(action);
}
@Override
public boolean containsKey(String key) throws SQLException {
try(
Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT 1 FROM metadata WHERE `key` = ?")
){
pstmt.setString(1, key);
try(ResultSet rs = pstmt.executeQuery()){
return rs.next();
}
}
}
@Override
public int entryCount() throws SQLException {
try(
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT COUNT(1) FROM metadata")
){
rs.next();
return rs.getInt(1);
}
}
}

22
src/main/resources/log4j2.xml

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<File name="RIlog" fileName="ri_log">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="org.leolo.nrdd">
<AppenderRef ref="Console" />
<AppenderRef ref="RIlog" />
</Logger>
</Loggers>
</Configuration>

5
src/test/java/org/leolo/nrdatad/AppTest.java → src/test/java/org/leolo/AppTest.java

@ -1,4 +1,4 @@
package org.leolo.nrdatad;
package org.leolo;
import static org.junit.Assert.assertTrue;
@ -7,7 +7,8 @@ import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
public class AppTest
{
/**
* Rigorous Test :-)
*/

92
src/test/java/org/leolo/nrdatad/ConfigurationTest.java

@ -1,92 +0,0 @@
package org.leolo.nrdatad;
import org.apache.logging.log4j.LogBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.Random;
import static org.junit.Assert.*;
public class ConfigurationTest {
public static final char[] randomChars = "1234567890qwertyuiopasdfghjklzxcvbnm".toCharArray();
private static Logger log = LogManager.getLogger();
private static String fileName;
@Before public void setUpClass(){
int round = 0;
while(true) {
fileName = "test-"+getRandomFileName()+".tmp";
log.always().log("File name is {}", fileName);
if(!new File(fileName).exists()){
break;
}
if(++round>48){
assertTrue("Cannot get a file name", false);
}
}
}
private static String getRandomFileName(){
StringBuilder sb = new StringBuilder();
Random r = new Random();
for(int i=0;i<16;i++){
sb.append(randomChars[r.nextInt(randomChars.length)]);
}
return sb.toString();
}
@Test public void basicLoad() throws Exception{
assertEquals("Dirty configs", 0, ConfigurationManager.getInstance().size());
//Step 1: Create a simple one
try(PrintWriter out = new PrintWriter(new File(fileName))){
out.println("key1=value1");
out.println("key2=value2");
out.println("key3=value3");
out.println("key4=value4");
out.println("#key5=value5");
}catch(IOException e){
log.always().withThrowable(e).log("Unable to test");
assert false;
}
ConfigurationManager.getInstance().loadConfiguration(fileName);
assertEquals("Config key count mismatch", 4, ConfigurationManager.getInstance().size());
assertEquals("Config key count mismatch", "value1", ConfigurationManager.getInstance().getProperty("key1"));
assertEquals("Config key count mismatch", "value3", ConfigurationManager.getInstance().getProperty("key3"));
assertEquals("Config key count mismatch", "value4", ConfigurationManager.getInstance().getProperty("key4"));
assertEquals("Config key count mismatch", "value2", ConfigurationManager.getInstance().getProperty("key2"));
assertEquals("Config key count mismatch", null, ConfigurationManager.getInstance().getProperty("key5"));
}
@Test public void notExistFile(){
assertEquals("Dirty configs", 0, ConfigurationManager.getInstance().size());
try {
ConfigurationManager.getInstance().loadConfiguration(fileName);
}catch(IOException e){
return;
}
assertFalse("Exception not thrown", true);
}
@After public void cleanUpEach(){
try {
Files.deleteIfExists(new File(fileName).toPath());
log.atInfo().log("Removed file {}", fileName);
} catch (IOException e) {
log.always().withThrowable(e).log("Unable to remove file");
}
ConfigurationManager.getInstance().clear();
}
@AfterClass public static void cleanup(){
new File(fileName).deleteOnExit();
}
}

28
src/test/java/org/leolo/nrdatad/db/test/DatabaseManager.java

@ -1,28 +0,0 @@
package org.leolo.nrdatad.db.test;
import org.leolo.nrdatad.db.MetadataDao;
import java.sql.Connection;
import java.sql.SQLException;
public class DatabaseManager implements org.leolo.nrdatad.db.DatabaseManager {
public void initPool() {
}
@Override
public boolean checkConnection() {
return true;
}
@Override
public Connection getConnection() throws SQLException {
throw new RuntimeException("Function not supported by stub");
}
@Override
public MetadataDao getMetadataDao() {
return null;
}
}

40
src/test/java/org/leolo/nrdatad/db/test/MetadataDao.java

@ -1,40 +0,0 @@
package org.leolo.nrdatad.db.test;
import org.jetbrains.annotations.NotNull;
import org.leolo.nrdatad.db.DatabaseManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Set;
import java.util.function.BiConsumer;
public class MetadataDao extends org.leolo.nrdatad.db.MetadataDao {
private HashMap<String, String> dataMap = new HashMap<>();
public MetadataDao(DatabaseManager manager) {
super(manager);
}
@Override
public String getMetadata(String key, String defaultValue) throws SQLException {
if(dataMap.containsKey(key))
return dataMap.get(key);
return defaultValue;
}
@Override
public void updateMetadata(String key, @NotNull String value) throws SQLException {
dataMap.put(key, value);
}
@Override
public Set<String> getKeys() throws SQLException {
return dataMap.keySet();
}
@Override
public void forEach(BiConsumer<String, String> action) throws SQLException {
dataMap.forEach(action);
}
}
Loading…
Cancel
Save