diff --git a/library/src/main/java/com/nucleocore/library/NucleoDB.java b/library/src/main/java/com/nucleocore/library/NucleoDB.java index de2c40e..44c555a 100644 --- a/library/src/main/java/com/nucleocore/library/NucleoDB.java +++ b/library/src/main/java/com/nucleocore/library/NucleoDB.java @@ -1,20 +1,14 @@ package com.nucleocore.library; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.google.common.collect.Queues; import com.nucleocore.library.database.modifications.Create; import com.nucleocore.library.database.tables.annotation.Conn; -import com.nucleocore.library.database.tables.connection.Connection; import com.nucleocore.library.database.tables.connection.ConnectionConfig; import com.nucleocore.library.database.tables.connection.ConnectionHandler; import com.nucleocore.library.database.tables.annotation.Index; -import com.nucleocore.library.database.tables.annotation.Relationship; -import com.nucleocore.library.database.tables.annotation.Relationships; import com.nucleocore.library.database.tables.annotation.Table; import com.nucleocore.library.database.utils.TreeSetExt; import com.nucleocore.library.database.utils.exceptions.IncorrectDataEntryClassException; import com.nucleocore.library.database.utils.exceptions.MissingDataEntryConstructorsException; -import com.nucleocore.library.database.utils.index.TreeIndex; import com.nucleocore.library.database.utils.sql.SQLHandler; import com.nucleocore.library.database.tables.table.DataTable; import com.nucleocore.library.database.tables.table.DataTableBuilder; @@ -30,13 +24,14 @@ import org.reflections.Reflections; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.logging.Logger; +import static com.nucleocore.library.utils.field.FieldFinder.getAllAnnotatedFields; + public class NucleoDB{ private static Logger logger = Logger.getLogger(DataTable.class.getName()); private TreeMap tables = new TreeMap<>(); @@ -136,6 +131,9 @@ private void startTables(String bootstrap, String[] packagesToScan, DBType dbTyp for (Class type : tableTypes) { Table tableAnnotation = type.getAnnotation(Table.class); String tableName = tableAnnotation.tableName(); + if(tableName.isEmpty()){ + tableName = type.getName().toLowerCase(); + } Class dataEntryClass = tableAnnotation.dataEntryClass(); if(!DataEntry.class.isAssignableFrom(dataEntryClass)){ throw new IncorrectDataEntryClassException(String.format("%s does not extend DataEntry", dataEntryClass.getName())); @@ -149,7 +147,9 @@ private void startTables(String bootstrap, String[] packagesToScan, DBType dbTyp } catch (NoSuchMethodException e) { throw new MissingDataEntryConstructorsException(String.format("%s does not have all DataEntry constructors overridden!", dataEntryClass.getName()), e); } - processTableClass(tableName, indexes, type); + + indexes.put(tableName, processIndexListForClass(type)); + switch (dbType) { case ALL -> tables.add(launchTable(bootstrap, tableName, dataEntryClass, type, new StartupRun(){ public void run(DataTable table) { @@ -169,7 +169,7 @@ public void run(DataTable table) { } } tables.stream().forEach(table -> { - table.setIndexes(indexes.get(table.getConfig().getTable()).toArray(new String[0])); + table.addIndexes(indexes.get(table.getConfig().getTable())); table.build(); }); try { @@ -181,130 +181,17 @@ public void run(DataTable table) { } } - public Set getAllRelated(DataEntry dataEntry) { - Set set = new TreeSetExt<>(); - if (dataEntry.getData().getClass().isAnnotationPresent(Table.class)) { - Table localTable = dataEntry.getData().getClass().getAnnotation(Table.class); - String localTableName = localTable.tableName(); - for (Relationship relationship : getRelationships(dataEntry.getData().getClass())) { - getRelatedByRelationship(dataEntry, set, localTableName, relationship); - } - } - return set; - } - - public Set getRelated(DataEntry dataEntry, Class clazz) { - Set set = new TreeSetExt<>(); - if (dataEntry.getData().getClass().isAnnotationPresent(Table.class)) { - Table localTable = dataEntry.getData().getClass().getAnnotation(Table.class); - String localTableName = localTable.tableName(); - for (Relationship relationship : getRelationships(dataEntry.getData().getClass())) { - if (relationship.clazz() == clazz) { - getRelatedByRelationship(dataEntry, set, localTableName, relationship); - } else { - //logger.info("Relation ignored"); - } - } - } - return set; - } - - public Set getRelatedRemote(DataEntry dataEntry, Class clazz, String index) { - Set set = new TreeSetExt<>(); - if (dataEntry.getData().getClass().isAnnotationPresent(Table.class)) { - Table localTable = dataEntry.getData().getClass().getAnnotation(Table.class); - String localTableName = localTable.tableName(); - for (Relationship relationship : getRelationships(dataEntry.getData().getClass())) { - if (relationship.clazz() == clazz && index.equals(relationship.remoteKey())) { - getRelatedByRelationship(dataEntry, set, localTableName, relationship); - } else { - //logger.info("Relation ignored"); - } - } - } - return set; - } - - public Set getRelatedLocal(DataEntry dataEntry, Class clazz, String index) { - Set set = new TreeSetExt<>(); - if (dataEntry.getData().getClass().isAnnotationPresent(Table.class)) { - Table localTable = dataEntry.getData().getClass().getAnnotation(Table.class); - String localTableName = localTable.tableName(); - for (Relationship relationship : getRelationships(dataEntry.getData().getClass())) { - if (relationship.clazz() == clazz && index.equals(relationship.localKey())) { - getRelatedByRelationship(dataEntry, set, localTableName, relationship); - } else { - //logger.info("Relation ignored"); - } - } - } - return set; - } - - private void getRelatedByRelationship(DataEntry dataEntry, Set set, String localTableName, Relationship relationship) { - if (relationship.clazz().isAnnotationPresent(Table.class)) { - Table remoteTable = (Table) relationship.clazz().getAnnotation(Table.class); - String remoteTableName = remoteTable.tableName(); - //logger.info("getting for relationship from " + localTableName + " to " + remoteTableName); - try { - //logger.info(relationship.localKey()); - List values = new TreeIndex().getValues(Queues.newLinkedBlockingDeque(Arrays.asList(relationship.localKey().split("\\."))), dataEntry.getData()); - if (values.size() > 0) { - for (Object value : values) { - set.addAll(this.getTable(remoteTableName).get(relationship.remoteKey(), value, null)); - } - } - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } else { - logger.info("Target class not a NucleoDB Table."); - } - - } - - private void processRelationship(String tableName, Map> indexes, Relationship relationship) { - indexes.get(tableName).add(relationship.localKey()); - if (relationship.clazz().isAnnotationPresent(Table.class)) { - String tableNameRemote = ((Table) relationship.clazz().getAnnotation(Table.class)).tableName(); - if (!indexes.containsKey(tableNameRemote)) { - processTableClass(tableNameRemote, indexes, relationship.clazz()); - } - indexes.get(tableNameRemote).add(relationship.remoteKey()); - } - } - - private List getRelationships(Class clazz) { - List relationships = new LinkedList<>(); - if (clazz.isAnnotationPresent(Relationship.class)) { - Relationship relationship = clazz.getAnnotation(Relationship.class); - relationships.add(relationship); - } - if (clazz.isAnnotationPresent(Relationships.class)) { - Relationships relationship = clazz.getAnnotation(Relationships.class); - relationships.addAll(Arrays.stream(relationship.value()).toList()); - } - return relationships; - } + private Set processIndexListForClass(Class clazz) { + Set indexes = new TreeSet<>(); - private void processTableClass(String tableName, Map> indexes, Class clazz) { - if (!indexes.containsKey(tableName)) { - indexes.put(tableName, new TreeSetExt<>()); - } - for (Field declaredField : clazz.getDeclaredFields()) { - if (declaredField.isAnnotationPresent(Index.class)) { - Index i = declaredField.getAnnotation(Index.class); - if (i.value().isEmpty()) { - indexes.get(tableName).addAll(Arrays.asList(declaredField.getName().toLowerCase())); - } else { - indexes.get(tableName).addAll(Arrays.asList(i.value())); - } + getAllAnnotatedFields(clazz, Index.class, "").forEach(field->{ + if (field.getAnnotation().value().isEmpty()) { + indexes.add(field.getPath()); + } else { + indexes.add(field.getAnnotation().value()); } - } - - for (Relationship relationship : getRelationships(clazz)) { - processRelationship(tableName, indexes, relationship); - } + }); + return indexes; } public Object sql(String sqlStr) throws JSQLParserException { diff --git a/library/src/main/java/com/nucleocore/library/database/modifications/ConnectionCreate.java b/library/src/main/java/com/nucleocore/library/database/modifications/ConnectionCreate.java index 901b152..48093b0 100644 --- a/library/src/main/java/com/nucleocore/library/database/modifications/ConnectionCreate.java +++ b/library/src/main/java/com/nucleocore/library/database/modifications/ConnectionCreate.java @@ -1,6 +1,8 @@ package com.nucleocore.library.database.modifications; +import com.fasterxml.jackson.core.JsonProcessingException; import com.nucleocore.library.database.tables.connection.Connection; +import com.nucleocore.library.database.utils.Serializer; import java.time.Instant; import java.util.Map; @@ -9,11 +11,9 @@ public class ConnectionCreate extends Modify { + private String connectionData; private String uuid; - private String fromKey; - private String toKey; private Instant date; - private Map metadata = new TreeMap<>(); public long version; public String changeUUID = UUID.randomUUID().toString(); @@ -24,22 +24,26 @@ public ConnectionCreate() { public ConnectionCreate(Connection connection) { this.date = connection.getDate(); - this.fromKey = connection.getFromKey(); - this.toKey = connection.getToKey(); this.uuid = connection.getUuid(); this.date = connection.getDate(); - this.metadata = connection.getMetadata(); this.version = connection.getVersion(); + try { + this.connectionData = Serializer.getObjectMapper().getOm().writeValueAsString(connection); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } public ConnectionCreate(String changeUUID, Connection connection) { this.changeUUID = changeUUID; - this.fromKey = connection.getFromKey(); - this.toKey = connection.getToKey(); this.uuid = connection.getUuid(); this.date = connection.getDate(); - this.metadata = connection.getMetadata(); this.version = connection.getVersion(); + try { + this.connectionData = Serializer.getObjectMapper().getOm().writeValueAsString(connection); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } public long getVersion() { @@ -66,22 +70,6 @@ public void setUuid(String uuid) { this.uuid = uuid; } - public String getFromKey() { - return fromKey; - } - - public void setFromKey(String fromKey) { - this.fromKey = fromKey; - } - - public String getToKey() { - return toKey; - } - - public void setToKey(String toKey) { - this.toKey = toKey; - } - public Instant getDate() { return date; } @@ -90,11 +78,11 @@ public void setDate(Instant date) { this.date = date; } - public Map getMetadata() { - return metadata; + public String getConnectionData() { + return connectionData; } - public void setMetadata(Map metadata) { - this.metadata = metadata; + public void setConnectionData(String connectionData) { + this.connectionData = connectionData; } } diff --git a/library/src/main/java/com/nucleocore/library/database/tables/connection/Connection.java b/library/src/main/java/com/nucleocore/library/database/tables/connection/Connection.java index aed6cab..8a90b74 100644 --- a/library/src/main/java/com/nucleocore/library/database/tables/connection/Connection.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/connection/Connection.java @@ -50,16 +50,6 @@ public Connection(F from, T to) { this.modified = Instant.now(); } - public Connection(ConnectionCreate connectionCreate) { - this.uuid = connectionCreate.getUuid(); - this.fromKey = connectionCreate.getFromKey(); - this.toKey = connectionCreate.getToKey();; - this.date = connectionCreate.getDate(); - this.version = connectionCreate.getVersion(); - this.metadata = new TreeMap<>(connectionCreate.getMetadata()); - - } - public T copy(Class clazz) { ObjectMapper om = new ObjectMapper() .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) diff --git a/library/src/main/java/com/nucleocore/library/database/tables/connection/ConnectionHandler.java b/library/src/main/java/com/nucleocore/library/database/tables/connection/ConnectionHandler.java index a3112d9..a799af1 100644 --- a/library/src/main/java/com/nucleocore/library/database/tables/connection/ConnectionHandler.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/connection/ConnectionHandler.java @@ -557,24 +557,25 @@ public void modify(Modification mod, Object modification) { case CONNECTIONCREATE: ConnectionCreate c = (ConnectionCreate) modification; - logger.info("Create statement called"); + //logger.info("Create statement called"); if (c != null) { itemProcessed(); if (this.config.getReadToTime() != null && c.getDate().isAfter(this.config.getReadToTime())) { - logger.info("Create after target db date"); + //logger.info("Create after target db date"); return; } try { if (connectionByUUID.containsKey(c.getUuid())) { - logger.info("Ignore already saved change."); + //logger.info("Ignore already saved change."); return; // ignore this create } - Connection connection = (Connection) getConfig().getConnectionClass().getDeclaredConstructor(ConnectionCreate.class).newInstance(c); - Serializer.log(connection); + + Connection connection = (Connection) Serializer.getObjectMapper().getOm().readValue(c.getConnectionData(), getConfig().getConnectionClass()); + this.addConnection(connection); - Serializer.log("Connection added to db"); - Serializer.log(consumers.asMap().keySet()); + //Serializer.log("Connection added to db"); + //Serializer.log(consumers.asMap().keySet()); this.changed = new Date().getTime(); if (c.getChangeUUID() != null) { Consumer consumer = consumers.getIfPresent(c.getChangeUUID()); @@ -594,35 +595,35 @@ public void modify(Modification mod, Object modification) { case CONNECTIONDELETE: try { ConnectionDelete d = (ConnectionDelete) modification; - logger.info("Delete statement called"); + //logger.info("Delete statement called"); if (d != null) { itemProcessed(); if (this.config.getReadToTime() != null && d.getTime().isAfter(this.config.getReadToTime())) { - logger.info("Delete after target db date"); + //logger.info("Delete after target db date"); //System.exit(1); return; } Connection conn = connectionByUUID.get(d.getUuid()); if (conn != null) { if (conn.getVersion() >= d.getVersion()) { - logger.info("Ignore already saved change."); + //logger.info("Ignore already saved change."); //System.exit(1); return; // ignore change } if (conn.getVersion() + 1 != d.getVersion()) { itemRequeue(); - Serializer.log("Version not ready!"); + //Serializer.log("Version not ready!"); modqueue.add(new ModificationQueueItem(mod, modification)); leftInModQueue.incrementAndGet(); synchronized (modqueue) { modqueue.notifyAll(); } } else { - logger.info("Deleted"); + //logger.info("Deleted"); this.removeConnection(conn); - logger.info("removed from db"); + //logger.info("removed from db"); deletedEntries.add(d.getUuid()); - logger.info("Added to deleted entries"); + //logger.info("Added to deleted entries"); this.changed = new Date().getTime(); if (d.getChangeUUID() != null) { Consumer consumer = consumers.getIfPresent(d.getChangeUUID()); @@ -641,7 +642,7 @@ public void modify(Modification mod, Object modification) { } } else { if (deletedEntries.contains(d.getUuid())) { - logger.info("already deleted conn "+d.getUuid()); + //logger.info("already deleted conn "+d.getUuid()); //System.exit(1); return; } else { diff --git a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTable.java b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTable.java index 2918264..83c71c9 100644 --- a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTable.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTable.java @@ -19,13 +19,12 @@ import com.nucleocore.library.database.utils.TreeSetExt; import com.nucleocore.library.database.utils.Utils; import com.nucleocore.library.database.utils.exceptions.IncorrectDataEntryObjectException; -import com.nucleocore.library.database.utils.index.Index; -import com.nucleocore.library.database.utils.index.TreeIndex; +import com.nucleocore.library.database.tables.table.index.Index; +import com.nucleocore.library.database.tables.table.index.TreeIndex; import com.nucleocore.library.kafkaLedger.ConsumerHandler; import com.nucleocore.library.kafkaLedger.ProducerHandler; import org.apache.kafka.clients.admin.*; import org.apache.kafka.common.config.TopicConfig; -import org.apache.kafka.common.errors.TopicExistsException; import com.github.fge.jsonpatch.JsonPatch; import java.io.File; @@ -49,16 +48,17 @@ public class DataTable implements Serializable{ @JsonIgnore private transient static Logger logger = Logger.getLogger(DataTable.class.getName()); - private Set entries = Sets.newTreeSet(); + private Set entries = new TreeSetExt<>(); private DataTableConfig config; - private Map indexes = new TreeMap<>(); - private Set dataEntries = new TreeSet<>(); + @JsonIgnore + private transient Map indexes = new TreeMap<>(); + private Set dataEntries = new TreeSetExt<>(); private Map keyToEntry = new TreeMap<>(); private Map partitionOffsets = new TreeMap<>(); private String consumerId = UUID.randomUUID().toString(); private long changed = new Date().getTime(); private transient AtomicInteger leftInModQueue = new AtomicInteger(0); - private Set deletedEntries = Sets.newTreeSet(); + private Set deletedEntries = new TreeSetExt<>(); @JsonIgnore private transient Queue indexQueue = Queues.newLinkedBlockingQueue(); @JsonIgnore @@ -112,10 +112,18 @@ public void loadSavedData() { this.changed = tmpTable.changed; this.entries = tmpTable.entries; this.consumerId = tmpTable.consumerId; - this.indexes = tmpTable.indexes; this.partitionOffsets = tmpTable.partitionOffsets; this.keyToEntry = tmpTable.keyToEntry; - this.entries.forEach(e -> e.setTableName(this.config.getTable())); + this.entries.forEach(e -> { + for (Index i : this.indexes.values()) { + try { + i.add(e); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + e.setTableName(this.config.getTable()); + }); } catch (IOException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { @@ -185,6 +193,12 @@ public void createTopics() { public DataTable(DataTableConfig config) { this.config = config; + config.getIndexes().stream().map(i -> new TreeIndex(i)).collect(Collectors.toSet()).forEach(i -> { + if (!this.indexes.containsKey(i.getIndexedKey())) { + this.indexes.put(i.getIndexedKey(), i); + } + }); + if (config.isLoadSave()) { loadSavedData(); } @@ -193,12 +207,6 @@ public DataTable(DataTableConfig config) { createTopics(); } - Arrays.stream(config.getIndexes()).map(i -> new TreeIndex(i)).collect(Collectors.toSet()).forEach(i -> { - if (!this.indexes.containsKey(i.getIndexedKey())) { - this.indexes.put(i.getIndexedKey(), i); - } - }); - this.fields = new ArrayList<>(){{ addAll(Arrays.asList(config.getClazz().getDeclaredFields())); addAll(Arrays.asList(config.getClazz().getSuperclass().getFields())); diff --git a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableBuilder.java b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableBuilder.java index 5ed5bdd..dec3ad0 100644 --- a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableBuilder.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableBuilder.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull; import java.time.Instant; +import java.util.Set; public class DataTableBuilder implements Comparable{ private static final long serialVersionUID = 1; @@ -94,18 +95,8 @@ public DataTableBuilder setTableFileName(String tableFileName) { return this; } - public DataTableBuilder setIndexes(String... indexes) { - int inLen = indexes.length; - int oldLen = this.config.getIndexes().length; - String[] newIndexArray = new String[inLen+oldLen]; - - for (int i = 0; i < inLen; i++) { - newIndexArray[i] = indexes[i]; - } - for (int i = 0; i < oldLen; i++) { - newIndexArray[inLen+i] = this.config.getIndexes()[i]; - } - this.config.setIndexes(newIndexArray); + public DataTableBuilder addIndexes(Set indexes) { + this.config.getIndexes().addAll(indexes); return this; } public DataTableBuilder setStartupRun(StartupRun startupRun) { diff --git a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableConfig.java b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableConfig.java index 9e05270..332362f 100644 --- a/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableConfig.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/table/DataTableConfig.java @@ -5,6 +5,8 @@ import java.io.Serializable; import java.time.Instant; +import java.util.Set; +import java.util.TreeSet; public class DataTableConfig implements Serializable{ private static final long serialVersionUID = 4416983891804575837L; @@ -20,7 +22,7 @@ public class DataTableConfig implements Serializable{ Class dataEntryClass; boolean read = true; boolean write = true; - String[] indexes = new String[0]; + Set indexes = new TreeSet<>(); @JsonIgnore private transient StartupRun startupRun = null; @@ -66,7 +68,7 @@ public boolean isWrite() { return write; } - public String[] getIndexes() { + public Set getIndexes() { return indexes; } @@ -107,7 +109,7 @@ public void setWrite(boolean write) { this.write = write; } - public void setIndexes(String[] indexes) { + public void setIndexes(Set indexes) { this.indexes = indexes; } diff --git a/library/src/main/java/com/nucleocore/library/database/utils/index/Index.java b/library/src/main/java/com/nucleocore/library/database/tables/table/index/Index.java similarity index 92% rename from library/src/main/java/com/nucleocore/library/database/utils/index/Index.java rename to library/src/main/java/com/nucleocore/library/database/tables/table/index/Index.java index 7b351a5..d62ca01 100644 --- a/library/src/main/java/com/nucleocore/library/database/utils/index/Index.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/table/index/Index.java @@ -1,4 +1,4 @@ -package com.nucleocore.library.database.utils.index; +package com.nucleocore.library.database.tables.table.index; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.Queues; @@ -25,7 +25,7 @@ public Index(String indexedKey) { public List getIndexValue(DataEntry dataEntry) throws JsonProcessingException { - return getValues(Queues.newLinkedBlockingDeque(Arrays.asList(this.indexedKeyStr.split("\\."))), dataEntry.getData()); + return getValues(Queues.newConcurrentLinkedQueue(Arrays.asList(this.indexedKeyStr.split("\\."))), dataEntry.getData()); /*String json = dataEntry.getReference().toString(); try (JsonReader reader = Json.createReader(new StringReader(json))) { System.out.println(json); @@ -71,7 +71,7 @@ public List getValues(Queue pointer, Object start) throws JsonPr //System.out.println(current.getClass().getName()); return ((Collection) current).stream().map(c-> { try { - return getValues(Queues.newLinkedBlockingDeque(pointer), c); + return getValues(Queues.newConcurrentLinkedQueue(pointer), c); } catch (JsonProcessingException e) { return new LinkedList(); } diff --git a/library/src/main/java/com/nucleocore/library/database/utils/index/TreeIndex.java b/library/src/main/java/com/nucleocore/library/database/tables/table/index/TreeIndex.java similarity index 98% rename from library/src/main/java/com/nucleocore/library/database/utils/index/TreeIndex.java rename to library/src/main/java/com/nucleocore/library/database/tables/table/index/TreeIndex.java index f831d1d..721bd14 100644 --- a/library/src/main/java/com/nucleocore/library/database/utils/index/TreeIndex.java +++ b/library/src/main/java/com/nucleocore/library/database/tables/table/index/TreeIndex.java @@ -1,4 +1,4 @@ -package com.nucleocore.library.database.utils.index; +package com.nucleocore.library.database.tables.table.index; import com.fasterxml.jackson.core.JsonProcessingException; import com.nucleocore.library.database.tables.table.DataEntry; diff --git a/library/src/main/java/com/nucleocore/library/examples/anime/AnimeTest.java b/library/src/main/java/com/nucleocore/library/examples/anime/AnimeTest.java index 6763ad4..7ee3cf4 100644 --- a/library/src/main/java/com/nucleocore/library/examples/anime/AnimeTest.java +++ b/library/src/main/java/com/nucleocore/library/examples/anime/AnimeTest.java @@ -15,6 +15,7 @@ import com.nucleocore.library.examples.anime.definitions.AnimeDE; import com.nucleocore.library.examples.anime.tables.Anime; import com.nucleocore.library.examples.anime.tables.User; +import com.nucleocore.library.examples.anime.tables.nested.VoiceActor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -37,6 +38,7 @@ public static void main(String[] args) throws IOException, InterruptedException, "com.nucleocore.library.examples.anime.tables", "com.nucleocore.library.examples.anime.connections" ); + logger.info(String.format("indexes: %s",Serializer.getObjectMapper().getOm().writeValueAsString(nucleoDB.getTable(Anime.class).getIndexes()))); logger.info(String.format("tables: %s", nucleoDB.getTables().keySet().stream().collect(Collectors.joining(", ")))); logger.info(String.format("connections: %s", nucleoDB.getConnections().keySet().stream().collect(Collectors.joining(", ")))); DataTable userTable = nucleoDB.getTable(User.class); @@ -57,6 +59,7 @@ public static void main(String[] args) throws IOException, InterruptedException, Anime a = new Anime(); a.setName(animeName); + a.getActors().add(new VoiceActor("Maaya Sakamoto")); a.setOwner("firestar"); AtomicReference animeReference = new AtomicReference<>(); @@ -75,6 +78,8 @@ public static void main(String[] args) throws IOException, InterruptedException, } catch (InterruptedException e) { e.printStackTrace(); } + //logger.info(String.format("indexes: %s",Serializer.getObjectMapper().getOm().writeValueAsString(nucleoDB.getTable(Anime.class).getIndexes()))); + AtomicReference userReference = new AtomicReference<>(); userTable.saveAsync(new User(userName, "me"), (dataEntry -> { @@ -92,7 +97,6 @@ public static void main(String[] args) throws IOException, InterruptedException, } try { String user = ((UserDE) userTable.getEntries().stream().findFirst().get()).getData().getUser(); - Serializer.log(user); }catch (Exception e){ e.printStackTrace(); } @@ -119,6 +123,12 @@ public static void main(String[] args) throws IOException, InterruptedException, WatchingConnection connection = (WatchingConnection)connectionOptional.stream().findFirst().get(); logger.info("connection found type is "+connection.getClass().getName()); logger.info("anime name is "+connection.toEntry().getData().getName()); + connection.setTime(555.222f); + try { + nucleoDB.getConnectionHandler(WatchingConnection.class).saveSync(connection); + } catch (InvalidConnectionException e) { + throw new RuntimeException(e); + } nucleoDB.getConnectionHandler(WatchingConnection.class).deleteSync(connectionOptional.stream().findFirst().get()); } diff --git a/library/src/main/java/com/nucleocore/library/examples/anime/connections/WatchingConnection.java b/library/src/main/java/com/nucleocore/library/examples/anime/connections/WatchingConnection.java index 5967649..1cbe408 100644 --- a/library/src/main/java/com/nucleocore/library/examples/anime/connections/WatchingConnection.java +++ b/library/src/main/java/com/nucleocore/library/examples/anime/connections/WatchingConnection.java @@ -4,6 +4,7 @@ import com.nucleocore.library.database.tables.annotation.Conn; import com.nucleocore.library.database.tables.connection.Connection; import com.nucleocore.library.database.tables.table.DataEntry; +import com.nucleocore.library.database.utils.SkipCopy; import com.nucleocore.library.examples.anime.definitions.AnimeDE; import com.nucleocore.library.examples.anime.definitions.UserDE; import com.nucleocore.library.examples.anime.tables.Anime; @@ -13,6 +14,8 @@ @Conn("WATCHING") public class WatchingConnection extends Connection{ + @SkipCopy + private static final long serialVersionUID = 1; public WatchingConnection() { } @@ -20,12 +23,17 @@ public WatchingConnection(UserDE from, AnimeDE to) { super(from, to); } - public WatchingConnection(ConnectionCreate connectionCreate) { - super(connectionCreate); - } - public WatchingConnection(UserDE from, AnimeDE to, Map metadata) { super(from, to, metadata); } + private float time = 0f; + + public float getTime() { + return time; + } + + public void setTime(float time) { + this.time = time; + } } diff --git a/library/src/main/java/com/nucleocore/library/examples/anime/tables/Anime.java b/library/src/main/java/com/nucleocore/library/examples/anime/tables/Anime.java index 07597ea..da5ca7b 100644 --- a/library/src/main/java/com/nucleocore/library/examples/anime/tables/Anime.java +++ b/library/src/main/java/com/nucleocore/library/examples/anime/tables/Anime.java @@ -15,7 +15,7 @@ public class Anime implements Serializable{ @Index() String name; List tags = new ArrayList<>(); - List actors; + List actors = new ArrayList<>(); String image; String owner; diff --git a/library/src/main/java/com/nucleocore/library/examples/anime/tables/nested/VoiceActor.java b/library/src/main/java/com/nucleocore/library/examples/anime/tables/nested/VoiceActor.java index c519a23..331683c 100644 --- a/library/src/main/java/com/nucleocore/library/examples/anime/tables/nested/VoiceActor.java +++ b/library/src/main/java/com/nucleocore/library/examples/anime/tables/nested/VoiceActor.java @@ -1,10 +1,13 @@ package com.nucleocore.library.examples.anime.tables.nested; +import com.nucleocore.library.database.tables.annotation.Index; + import java.io.Serializable; import java.util.List; public class VoiceActor implements Serializable{ private static final long serialVersionUID = 1; + @Index String name; String character; diff --git a/library/src/main/java/com/nucleocore/library/utils/field/FieldFinder.java b/library/src/main/java/com/nucleocore/library/utils/field/FieldFinder.java new file mode 100644 index 0000000..2438c15 --- /dev/null +++ b/library/src/main/java/com/nucleocore/library/utils/field/FieldFinder.java @@ -0,0 +1,83 @@ +package com.nucleocore.library.utils.field; + +import com.nucleocore.library.database.tables.annotation.Index; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class FieldFinder{ + public static class FieldAndPath { + Field field; + String path; + T annotation; + + public FieldAndPath(Field field, String path, T annotation) { + this.field = field; + this.path = path; + this.annotation = annotation; + } + + public Field getField() { + return field; + } + + public void setField(Field field) { + this.field = field; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public T getAnnotation() { + return annotation; + } + + public void setAnnotation(T annotation) { + this.annotation = annotation; + } + } + public static List> getAllAnnotatedFields(Class clazz, Class annotationClass, String prefix) { + List> fieldsWithAnnotation = new ArrayList<>(); + // Process all fields in the class + for (Field field : clazz.getDeclaredFields()) { + // Check for the annotation directly on the field + String fieldName = field.getName(); + if (field.isAnnotationPresent(annotationClass)) { + T annotation = field.getAnnotation(annotationClass); + fieldsWithAnnotation.add(new FieldAndPath(field, prefix+fieldName, annotation)); + } + + // Check if the field is a class, an iterable, or a map + Class fieldType = field.getType(); + if (Iterable.class.isAssignableFrom(fieldType) || Map.class.isAssignableFrom(fieldType)) { + // Extract generic type and process it + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments(); + for (Type typeArg : actualTypeArguments) { + if (typeArg instanceof Class) { + fieldsWithAnnotation.addAll(getAllAnnotatedFields((Class) typeArg, annotationClass, prefix+fieldName+".")); + } + } + } + } else if (fieldType.isMemberClass()) { + fieldsWithAnnotation.addAll(getAllAnnotatedFields(fieldType, annotationClass, prefix+fieldName+".")); + } + } + // Process nested classes + for (Class nestedClass : clazz.getDeclaredClasses()) { + fieldsWithAnnotation.addAll(getAllAnnotatedFields(nestedClass, annotationClass, "")); + } + return fieldsWithAnnotation; + } +} diff --git a/memcache/src/main/java/com/nucleocore/memcache/ClientHandler.java b/memcache/src/main/java/com/nucleocore/memcache/ClientHandler.java index 8fdbebd..8612560 100644 --- a/memcache/src/main/java/com/nucleocore/memcache/ClientHandler.java +++ b/memcache/src/main/java/com/nucleocore/memcache/ClientHandler.java @@ -4,7 +4,7 @@ import com.nucleocore.library.database.tables.table.DataEntry; import com.nucleocore.library.database.utils.Serializer; import com.nucleocore.library.database.utils.exceptions.IncorrectDataEntryObjectException; -import com.nucleocore.library.database.utils.index.TreeIndex; +import com.nucleocore.library.database.tables.table.index.TreeIndex; import java.io.*; import java.net.*; diff --git a/memcache/src/main/java/com/nucleocore/memcache/NDBMemcache.java b/memcache/src/main/java/com/nucleocore/memcache/NDBMemcache.java index 7ec0fd7..fc2dadd 100644 --- a/memcache/src/main/java/com/nucleocore/memcache/NDBMemcache.java +++ b/memcache/src/main/java/com/nucleocore/memcache/NDBMemcache.java @@ -30,7 +30,7 @@ public void run(DataTable table) { e.printStackTrace(); } } - }).setIndexes("name").build(); + }).addIndexes("name").build(); } diff --git a/repository/build.gradle b/repository/build.gradle index ce2b64e..8a05c88 100644 --- a/repository/build.gradle +++ b/repository/build.gradle @@ -23,7 +23,7 @@ repositories { } dependencies { - implementation 'com.nucleodb:library:1.11.4' + implementation 'com.nucleodb:library:1.11.5' implementation 'org.springframework:spring-beans' implementation 'org.springframework:spring-context' implementation 'org.springframework:spring-expression' diff --git a/testapps/build.gradle b/testapps/build.gradle index b21ec7e..6d506d6 100644 --- a/testapps/build.gradle +++ b/testapps/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'com.nucleodb:library:1.11.4' + implementation 'com.nucleodb:library:1.11.5' implementation(project(':repository')) implementation("io.minio:minio:8.5.6") implementation('org.springframework.boot:spring-boot-starter-websocket') diff --git a/testapps/src/main/java/com/nucleocore/test/spring/AnimeController.java b/testapps/src/main/java/com/nucleocore/test/spring/AnimeController.java index 8ec13c1..17609a8 100644 --- a/testapps/src/main/java/com/nucleocore/test/spring/AnimeController.java +++ b/testapps/src/main/java/com/nucleocore/test/spring/AnimeController.java @@ -2,7 +2,9 @@ import com.nucleocore.test.common.Anime; import com.nucleocore.test.common.AnimeDE; +import com.nucleocore.test.common.WatchingConnection; import com.nucleocore.test.spring.repo.AnimeRepository; +import com.nucleocore.test.spring.repo.WatchingConnectionRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.web.bind.annotation.GetMapping; @@ -16,6 +18,8 @@ public class AnimeController{ @Autowired AnimeRepository animeRepository; + @Autowired + WatchingConnectionRepository watchingConnectionRepository; @GetMapping("/") public List test(){ @@ -35,4 +39,10 @@ public Optional idTest(){ public AnimeDE queryTest(){ return animeRepository.findByName("test"); } + + @GetMapping + public void createRelationship(){ + + watchingConnectionRepository.save(new WatchingConnection()); + } }