diff --git a/pom.xml b/pom.xml
index 2929837..8424107 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
org.listware
core
- 1.0
+ 1.1
jar
@@ -84,13 +84,13 @@
org.listware
io
- 1.0
+ 1.1
provided
org.listware
proto
- 1.0
+ 1.1
diff --git a/src/main/java/org/listware/core/FunctionContext.java b/src/main/java/org/listware/core/FunctionContext.java
index c4d8f61..0db0c76 100644
--- a/src/main/java/org/listware/core/FunctionContext.java
+++ b/src/main/java/org/listware/core/FunctionContext.java
@@ -3,25 +3,26 @@
package org.listware.core;
import org.apache.flink.statefun.sdk.Context;
-import org.apache.flink.statefun.sdk.FunctionType;
-import org.apache.flink.statefun.sdk.reqreply.generated.TypedValue;
import org.listware.sdk.Functions;
-import org.listware.io.utils.TypedValueDeserializer;
+import org.listware.core.cmdb.Cmdb.SystemKeys;
import org.listware.core.documents.ObjectDocument;
-import org.listware.core.provider.utils.Cmdb.Matcher;
-import org.listware.core.provider.utils.Cmdb.SystemKeys;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FunctionContext {
+ @SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(FunctionContext.class);
private Context flinkContext;
private ObjectDocument document;
private Functions.FunctionContext functionContext;
- private boolean isExecutedCallback = false;
+
+
+ private class Matcher {
+ public static final String UUID_V4_STRING = "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[89abAB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}";
+ public static final String NUMERIC_STRING = "\\d+";
+ }
public FunctionContext(Context context, ObjectDocument document, Functions.FunctionContext functionContext) {
this.flinkContext = context;
@@ -88,30 +89,4 @@ public class FunctionContext {
public boolean isType() {
return (!isRoot() && !isObjects() && !isTypes() && !isLink() && !isObject());
}
-
- // You can execute callback only once, getCallback() to inherit func or
- // Callback() after invoke
- public void callback() throws Exception {
- Functions.FunctionContext callback = getCallback();
- if (callback != null) {
- String namespace = callback.getFunctionType().getNamespace();
- String type = callback.getFunctionType().getType();
- FunctionType functionType = new FunctionType(namespace, type);
-
- LOG.info("send: " + functionType + " id " + callback.getId());
-
- TypedValue typedValue = TypedValueDeserializer.fromMessageLite(callback);
- ;
-
- flinkContext.send(functionType, callback.getId(), typedValue);
- }
- }
-
- public Functions.FunctionContext getCallback() {
- if (functionContext.hasCallback() && !isExecutedCallback) {
- isExecutedCallback = true;
- return functionContext.getCallback();
- }
- return null;
- }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/listware/core/Module.java b/src/main/java/org/listware/core/Module.java
index 88c27d8..2c9a2b0 100644
--- a/src/main/java/org/listware/core/Module.java
+++ b/src/main/java/org/listware/core/Module.java
@@ -8,14 +8,16 @@ import com.google.auto.service.AutoService;
import org.apache.flink.statefun.sdk.spi.StatefulFunctionModule;
import org.listware.core.provider.FunctionProvider;
-import org.listware.core.provider.functions.Link;
import org.listware.core.provider.functions.Log;
-import org.listware.core.provider.functions.Object;
-import org.listware.core.provider.functions.ObjectTrigger;
import org.listware.core.provider.functions.Register;
import org.listware.core.provider.functions.Router;
-import org.listware.core.provider.functions.Type;
-import org.listware.core.provider.functions.TypeTrigger;
+import org.listware.core.provider.functions.link.AdvancedLink;
+import org.listware.core.provider.functions.link.LinkTrigger;
+import org.listware.core.provider.functions.object.Link;
+import org.listware.core.provider.functions.object.Object;
+import org.listware.core.provider.functions.object.ObjectTrigger;
+import org.listware.core.provider.functions.object.Type;
+import org.listware.core.provider.functions.object.TypeTrigger;
@AutoService(StatefulFunctionModule.class)
public final class Module implements StatefulFunctionModule {
@@ -31,5 +33,7 @@ public final class Module implements StatefulFunctionModule {
binder.bindFunctionProvider(Router.FUNCTION_TYPE, provider);
binder.bindFunctionProvider(Log.FUNCTION_TYPE, provider);
binder.bindFunctionProvider(Register.FUNCTION_TYPE, provider);
+ binder.bindFunctionProvider(AdvancedLink.FUNCTION_TYPE, provider);
+ binder.bindFunctionProvider(LinkTrigger.FUNCTION_TYPE, provider);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/listware/core/cmdb/Cmdb.java b/src/main/java/org/listware/core/cmdb/Cmdb.java
new file mode 100644
index 0000000..573de1c
--- /dev/null
+++ b/src/main/java/org/listware/core/cmdb/Cmdb.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2022
+ * Listware
+ */
+
+package org.listware.core.cmdb;
+
+import org.apache.flink.statefun.sdk.Context;
+import org.apache.flink.statefun.sdk.reqreply.generated.TypedValue;
+import org.listware.core.documents.LinkDocument;
+import org.listware.core.documents.ObjectDocument;
+import org.listware.core.provider.functions.link.LinkTrigger;
+import org.listware.core.provider.functions.object.ObjectTrigger;
+import org.listware.core.utils.exceptions.AlreadyLinkException;
+import org.listware.core.utils.exceptions.NoLinkException;
+import org.listware.core.utils.exceptions.UnknownIdException;
+import org.listware.io.grpc.FinderClient;
+import org.listware.io.grpc.QDSLClient;
+import org.listware.io.utils.TypedValueDeserializer;
+import org.listware.sdk.Functions;
+import org.listware.sdk.pbcmdb.Core;
+import org.listware.sdk.pbcmdb.pbfinder.Finder;
+import org.listware.sdk.pbcmdb.pbqdsl.QDSL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.protobuf.ByteString;
+
+public class Cmdb {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(Cmdb.class);
+
+ // Constant system cmdb keys
+ public class SystemKeys {
+ public static final String ROOT = "root";
+ public static final String OBJECTS = "objects";
+ public static final String TYPES = "types";
+ }
+
+ // Collection names
+ public class Collections {
+ public static final String SYSTEM = "system";
+ public static final String TYPES = "types";
+ public static final String OBJECTS = "objects";
+ public static final String LINKS = "links";
+ }
+
+ // Link entries
+ public class LinkTypes {
+ public static final String TYPE = "type";
+ public static final String SYSTEM = "system";
+ }
+
+ private ObjectClient objectClient = new ObjectClient();
+ public LinkClient linkClient = new LinkClient();
+ public QDSLClient qdslClient = new QDSLClient();
+ public FinderClient finderClient = new FinderClient();
+
+ public void shutdown() throws InterruptedException {
+ objectClient.shutdown();
+ linkClient.shutdown();
+ qdslClient.shutdown();
+ finderClient.shutdown();
+ }
+
+ // R same for types/objects/system
+ public ObjectDocument readDocument(String id) throws Exception {
+ return objectClient.readDocument(id);
+ }
+
+ private ObjectDocument updateDocument(ObjectDocument document) throws Exception {
+ document = objectClient.updateDocument(document.getId(), document.serialize());
+ LOG.info("updated " + document.getId());
+ return document;
+ }
+
+ // D same for types/objects/system
+ private void removeDocument(ObjectDocument document) throws Exception {
+ objectClient.removeDocument(document.getId());
+ LOG.info("deleted " + document.getId());
+ }
+
+ // R links
+ public LinkDocument readLinkDocument(String id) throws Exception {
+ return linkClient.readDocument(id);
+ }
+
+ public LinkDocument readLinkDocument(String from, String name) throws Exception {
+ Finder.Response response = finderClient.from(from, name);
+ if (response.getLinksCount() == 0) {
+ throw new NoLinkException(from, name);
+ }
+ return LinkDocument.deserialize(response.getLinks(0).getPayload());
+ }
+
+ // do not duplicate link with name
+ public void checkFrom(ObjectDocument parent, String name) throws Exception {
+ Finder.Response response = finderClient.from(parent.getId(), name);
+ if (response.getLinksCount() > 0) {
+ throw new AlreadyLinkException(parent.getId(), name);
+ }
+ }
+
+ public LinkDocument updateLinkDocument(LinkDocument document) throws Exception {
+ document = linkClient.updateDocument(document.getId(), document.serialize());
+ LOG.info("updated " + document.getId());
+ return document;
+ }
+
+ // D links
+ public void removeDocument(LinkDocument document) throws Exception {
+ linkClient.removeDocument(document.getId());
+ LOG.info("deleted " + document.getId());
+ }
+
+ /*******************************************************************************************/
+ // C for SYSTEM
+ public ObjectDocument createSystem(ObjectDocument document) throws Exception {
+ document = objectClient.createDocument(Collections.SYSTEM, document.serialize());
+
+ LOG.info("created system " + document.getId());
+
+ return document;
+ }
+
+ public ObjectDocument createSystem(ObjectDocument parent, ObjectDocument document) throws Exception {
+ document = objectClient.createDocument(Collections.SYSTEM, document.serialize());
+
+ LOG.info("created system " + document.getId());
+
+ // link root -> object
+ createLink(parent, document, LinkTypes.SYSTEM, document.getKey());
+
+ return document;
+ }
+
+ /*******************************************************************************************/
+
+ // types C
+ public ObjectDocument createType(ObjectDocument document) throws Exception {
+ document = objectClient.createDocument(Collections.TYPES, document.serialize());
+
+ ObjectDocument types = readDocument("system/types");
+
+ // link from types -> type
+ createLink(types, document, LinkTypes.TYPE, document.getKey());
+
+ LOG.info("created type " + document.getId());
+
+ return document;
+ }
+
+ public ObjectDocument updateType(Context context, ObjectDocument document) throws Exception {
+ document = updateDocument(document);
+
+ return document;
+ }
+
+ public void removeType(Context context, ObjectDocument document) throws Exception {
+ removeDocument(document);
+ }
+
+ /*******************************************************************************************/
+
+ // only from type
+ public ObjectDocument createObject(ObjectDocument type, ObjectDocument document) throws Exception {
+ ObjectDocument objects = readDocument("system/objects");
+
+ document = objectClient.createDocument(Collections.OBJECTS, document.serialize());
+
+ // link type -> object ($uuid)
+ createLink(type, document, type.getKey(), document.getKey());
+
+ // link objects -> object ($uuid)
+ createLink(objects, document, type.getKey(), document.getKey());
+
+ LOG.info("created object " + document.getId());
+
+ return document;
+ }
+
+ public ObjectDocument createObject(Context context, ObjectDocument type, ObjectDocument document) throws Exception {
+ document = createObject(type, document);
+
+ Functions.FunctionContext pbFunctionContext = ObjectTrigger.Trigger(document.getId(), Core.Method.CREATE);
+
+ TypedValue typedValue = TypedValueDeserializer.fromMessageLite(pbFunctionContext);
+
+ context.send(ObjectTrigger.FUNCTION_TYPE, document.getId(), typedValue);
+
+ return document;
+ }
+
+ // with parent
+ public ObjectDocument createObject(ObjectDocument type, ObjectDocument parent, ObjectDocument document, String name)
+ throws Exception {
+
+ checkFrom(parent, name);
+
+ document = createObject(type, document);
+
+ // link parent -> object ($uuid)
+ createLink(parent, document, type.getKey(), name);
+
+ return document;
+ }
+
+ public ObjectDocument createObject(Context context, ObjectDocument type, ObjectDocument parent,
+ ObjectDocument document, String name) throws Exception {
+
+ checkFrom(parent, name);
+
+ document = createObject(context, type, document);
+
+ // link parent -> object ($uuid)
+ createLink(parent, document, type.getKey(), name);
+
+ return document;
+ }
+
+ public ObjectDocument updateObject(Context context, ObjectDocument document) throws Exception {
+ document = updateDocument(document);
+ Functions.FunctionContext pbFunctionContext = ObjectTrigger.Trigger(document.getId(), Core.Method.UPDATE);
+ TypedValue typedValue = TypedValueDeserializer.fromMessageLite(pbFunctionContext);
+ context.send(ObjectTrigger.FUNCTION_TYPE, document.getId(), typedValue);
+
+ return document;
+ }
+
+ public void removeObject(Context context, ObjectDocument document) throws Exception {
+ removeDocument(document);
+ // move trigger to link type -> objects
+
+// Functions.FunctionContext pbFunctionContext = ObjectTrigger.Trigger(document.getId(), Core.Method.DELETE);
+//
+// TypedValue typedValue = TypedValueDeserializer.fromMessageLite(pbFunctionContext);
+//
+// context.send(ObjectTrigger.FUNCTION_TYPE, document.getId(), typedValue);
+ }
+
+ // Links
+
+ public LinkDocument createLink(ObjectDocument parent, ObjectDocument document, String type, String name)
+ throws Exception {
+
+ checkFrom(parent, name);
+
+ LinkDocument link = new LinkDocument(parent.getId(), document.getId(), type, name);
+
+ link = linkClient.createDocument(Collections.LINKS, link.serialize());
+
+ LOG.info("created link" + link.getId());
+
+ return link;
+ }
+
+ public LinkDocument createLink(ObjectDocument parent, ObjectDocument document, String type, String name,
+ ByteString payload) throws Exception {
+
+ checkFrom(parent, name);
+
+ LinkDocument link = new LinkDocument(parent.getId(), document.getId(), type, name);
+ link.replaceProperties(payload);
+
+ link = linkClient.createDocument(Collections.LINKS, link.serialize());
+
+ LOG.info("created link" + link.getId());
+
+ return link;
+ }
+
+ public LinkDocument createLink(Context context, ObjectDocument parent, ObjectDocument document, String type,
+ String name, ByteString payload) throws Exception {
+
+ LinkDocument link = createLink(parent, document, type, name, payload);
+
+ Functions.FunctionContext pbFunctionContext = LinkTrigger.Trigger(link.getId(), Core.Method.CREATE);
+
+ TypedValue typedValue = TypedValueDeserializer.fromMessageLite(pbFunctionContext);
+
+ context.send(LinkTrigger.FUNCTION_TYPE, link.getId(), typedValue);
+
+ LOG.info("created link" + link.getId());
+
+ return link;
+ }
+
+ public LinkDocument updateLink(Context context, LinkDocument document) throws Exception {
+ document = updateLinkDocument(document);
+
+ Functions.FunctionContext pbFunctionContext = LinkTrigger.Trigger(document.getId(), Core.Method.UPDATE);
+
+ TypedValue typedValue = TypedValueDeserializer.fromMessageLite(pbFunctionContext);
+
+ context.send(LinkTrigger.FUNCTION_TYPE, document.getId(), typedValue);
+
+ return document;
+ }
+
+ public void bootstrap() throws Exception {
+ ObjectDocument root = null;
+ try {
+ root = readDocument("system/root");
+ } catch (Exception ex) {
+ LOG.error(ex.getLocalizedMessage());
+ root = new ObjectDocument(SystemKeys.ROOT);
+ root = createSystem(root);
+ }
+
+ ObjectDocument objects = null;
+ try {
+ objects = readDocument("system/objects");
+ } catch (Exception ex) {
+ LOG.error(ex.getLocalizedMessage());
+ objects = new ObjectDocument(SystemKeys.OBJECTS);
+ objects = createSystem(root, objects);
+ }
+
+ ObjectDocument types = null;
+ try {
+ types = readDocument("system/types");
+ } catch (Exception ex) {
+ LOG.error(ex.getLocalizedMessage());
+ types = new ObjectDocument(SystemKeys.TYPES);
+ types = createSystem(root, types);
+ }
+
+ ObjectDocument functionContainer = null;
+ try {
+ functionContainer = readDocument("types/function-container");
+ } catch (Exception ex) {
+ LOG.error(ex.getLocalizedMessage());
+ functionContainer = new ObjectDocument("function-container");
+ functionContainer = createType(functionContainer);
+ }
+
+ ObjectDocument function = null;
+ try {
+ function = readDocument("types/function");
+ } catch (Exception ex) {
+ LOG.error(ex.getLocalizedMessage());
+ function = new ObjectDocument("function");
+ function = createType(function);
+ }
+
+ QDSL.Options options = QDSL.Options.newBuilder().build();
+
+ QDSL.Elements elements = qdslClient.qdsl("functions.root", options);
+ ObjectDocument functions = null;
+ if (elements.getElementsCount() == 0) {
+ functions = new ObjectDocument();
+ functions = createObject(function, root, functions, "functions");
+ } else {
+ functions = readDocument(elements.getElements(0).getId());
+ }
+
+ elements = qdslClient.qdsl("system.functions.root", options);
+ ObjectDocument system = null;
+ if (elements.getElementsCount() == 0) {
+ system = new ObjectDocument();
+ system = createObject(functionContainer, functions, system, "system");
+ } else {
+ system = readDocument(elements.getElements(0).getId());
+ }
+
+ elements = qdslClient.qdsl("types.system.functions.root", options);
+ ObjectDocument typesFunction = null;
+ if (elements.getElementsCount() == 0) {
+ typesFunction = new ObjectDocument();
+ typesFunction = createObject(function, system, typesFunction, "types");
+ } else {
+ typesFunction = readDocument(elements.getElements(0).getId());
+ }
+
+ elements = qdslClient.qdsl("objects.system.functions.root", options);
+ ObjectDocument objectsFunction = null;
+ if (elements.getElementsCount() == 0) {
+ objectsFunction = new ObjectDocument();
+ objectsFunction = createObject(function, system, objectsFunction, "objects");
+ } else {
+ objectsFunction = readDocument(elements.getElements(0).getId());
+ }
+
+ elements = qdslClient.qdsl("links.system.functions.root", options);
+ ObjectDocument linksFunction = null;
+ if (elements.getElementsCount() == 0) {
+ linksFunction = new ObjectDocument();
+ linksFunction = createObject(function, system, linksFunction, "links");
+ } else {
+ linksFunction = readDocument(elements.getElements(0).getId());
+ }
+ }
+
+ public String getTypeId(String id) throws Exception {
+ QDSL.Options options = QDSL.Options.newBuilder().setType(true).build();
+
+ String query = String.format("*[?@._id == '%s'?].objects", id);
+
+ QDSL.Elements elements = qdslClient.qdsl(query, options);
+
+ for (QDSL.Element element : elements.getElementsList()) {
+ return "types/" + element.getType();
+ }
+ throw new UnknownIdException(id);
+ }
+
+}
diff --git a/src/main/java/org/listware/core/cmdb/LinkClient.java b/src/main/java/org/listware/core/cmdb/LinkClient.java
new file mode 100644
index 0000000..26e6857
--- /dev/null
+++ b/src/main/java/org/listware/core/cmdb/LinkClient.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022
+ * Listware
+ */
+
+package org.listware.core.cmdb;
+
+import org.listware.core.documents.LinkDocument;
+import org.listware.core.utils.exceptions.PayloadNotFoundException;
+import org.listware.core.utils.exceptions.UnknownIdException;
+import org.listware.io.grpc.EdgeClient;
+import org.listware.sdk.pbcmdb.Core;
+
+import com.google.protobuf.ByteString;
+
+public class LinkClient extends EdgeClient {
+
+ public LinkDocument createDocument(String collection, ByteString payload) throws Exception {
+ Core.Response resp = create(collection, payload);
+ return LinkDocument.deserialize(resp.getPayload());
+ }
+
+ public LinkDocument readDocument(String id) throws Exception {
+ Parser parser = new Parser(id);
+ Core.Response resp = read(parser.getCollection(), parser.getKey());
+ if (resp.getPayload().isEmpty()) {
+ throw new PayloadNotFoundException();
+ }
+ return LinkDocument.deserialize(resp.getPayload());
+ }
+
+ public LinkDocument updateDocument(String id, ByteString payload) throws Exception {
+ Parser parser = new Parser(id);
+ Core.Response resp = update(parser.getCollection(), parser.getKey(), payload);
+ if (resp.getPayload().isEmpty()) {
+ throw new PayloadNotFoundException();
+ }
+ return LinkDocument.deserialize(resp.getPayload());
+ }
+
+ public void removeDocument(String id) throws Exception {
+ Parser parser = new Parser(id);
+ remove(parser.getCollection(), parser.getKey());
+ }
+
+ class Parser {
+ private String collection;
+ private String key;
+
+ public Parser(String id) throws Exception {
+ String[] separated = id.split("\\/");
+ if (separated.length < 2) {
+ throw new UnknownIdException(id);
+ }
+ this.collection = separated[0];
+ this.key = separated[1];
+ }
+
+ public String getCollection() {
+ return collection;
+ }
+
+ public void setCollection(String collection) {
+ this.collection = collection;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+ }
+
+}
diff --git a/src/main/java/org/listware/core/cmdb/ObjectClient.java b/src/main/java/org/listware/core/cmdb/ObjectClient.java
new file mode 100644
index 0000000..8f8f75e
--- /dev/null
+++ b/src/main/java/org/listware/core/cmdb/ObjectClient.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022
+ * Listware
+ */
+
+package org.listware.core.cmdb;
+
+import org.listware.core.documents.ObjectDocument;
+import org.listware.core.utils.exceptions.PayloadNotFoundException;
+import org.listware.core.utils.exceptions.UnknownIdException;
+import org.listware.io.grpc.VertexClient;
+import org.listware.sdk.pbcmdb.Core;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.protobuf.ByteString;
+
+public class ObjectClient extends VertexClient {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(ObjectClient.class);
+
+ public ObjectDocument createDocument(String collection, ByteString payload) throws Exception {
+ Core.Response resp = create(collection, payload);
+ return ObjectDocument.deserialize(resp.getPayload());
+ }
+
+ public ObjectDocument readDocument(String id) throws Exception {
+ Parser parser = new Parser(id);
+ Core.Response resp = read(parser.getCollection(), parser.getKey());
+ if (resp.getPayload().isEmpty()) {
+ throw new PayloadNotFoundException();
+ }
+ return ObjectDocument.deserialize(resp.getPayload());
+ }
+
+ public ObjectDocument updateDocument(String id, ByteString payload) throws Exception {
+ Parser parser = new Parser(id);
+ Core.Response resp = update(parser.getCollection(), parser.getKey(), payload);
+ if (resp.getPayload().isEmpty()) {
+ throw new PayloadNotFoundException();
+ }
+ return ObjectDocument.deserialize(resp.getPayload());
+ }
+
+ public void removeDocument(String id) throws Exception {
+ Parser parser = new Parser(id);
+ remove(parser.getCollection(), parser.getKey());
+ }
+
+ class Parser {
+ private String collection;
+ private String key;
+
+ public Parser(String id) throws Exception {
+ String[] separated = id.split("\\/");
+ if (separated.length < 2) {
+ throw new UnknownIdException(id);
+ }
+
+ this.collection = separated[0];
+ this.key = separated[1];
+ }
+
+ public String getCollection() {
+ return collection;
+ }
+
+ public void setCollection(String collection) {
+ this.collection = collection;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+ }
+
+}
diff --git a/src/main/java/org/listware/core/cmdb/RegisterMessage.java b/src/main/java/org/listware/core/cmdb/RegisterMessage.java
new file mode 100644
index 0000000..5d28446
--- /dev/null
+++ b/src/main/java/org/listware/core/cmdb/RegisterMessage.java
@@ -0,0 +1,107 @@
+/* Copyright 2022 Listware */
+
+package org.listware.core.cmdb;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.listware.core.provider.functions.Register;
+import org.listware.sdk.pbcmdb.Core;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RegisterMessage {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(Register.class);
+
+ private List types = new ArrayList<>();
+ private List objects = new ArrayList<>();;
+ private List links = new ArrayList<>();;
+
+ public RegisterMessage() {
+ // POJO
+ }
+
+ public RegisterMessage(Core.RegisterMessage registerMessage) {
+ registerMessage.getTypeMessagesList().forEach(msg -> types.add(msg.toByteArray()));
+ registerMessage.getObjectMessagesList().forEach(msg -> objects.add(msg.toByteArray()));
+ registerMessage.getLinkMessagesList().forEach(msg -> links.add(msg.toByteArray()));
+ }
+
+ public List getTypes() {
+ return types;
+ }
+
+ public void setTypes(List types) {
+ this.types = types;
+ }
+
+ public List getObjects() {
+ return objects;
+ }
+
+ public void setObjects(List objects) {
+ this.objects = objects;
+ }
+
+ public List getLinks() {
+ return links;
+ }
+
+ public void setLinks(List links) {
+ this.links = links;
+ }
+
+ public List listTypes() throws Exception {
+ List registerMessages = new ArrayList<>();
+
+ Iterator iterator = types.iterator();
+ while (iterator.hasNext()) {
+ byte[] data = iterator.next();
+ Core.RegisterTypeMessage registerMessage = Core.RegisterTypeMessage.parseFrom(data);
+ registerMessages.add(registerMessage);
+ iterator.remove();
+ if (!registerMessage.getAsync()) {
+ return registerMessages;
+ }
+ }
+
+ return registerMessages;
+ }
+
+ public List listObjects() throws Exception {
+ List registerMessages = new ArrayList<>();
+
+ Iterator iterator = objects.iterator();
+ while (iterator.hasNext()) {
+ byte[] data = iterator.next();
+ Core.RegisterObjectMessage registerMessage = Core.RegisterObjectMessage.parseFrom(data);
+ registerMessages.add(registerMessage);
+ iterator.remove();
+ if (!registerMessage.getAsync()) {
+ return registerMessages;
+ }
+ }
+
+ return registerMessages;
+ }
+
+ public List listLinks() throws Exception {
+ List registerMessages = new ArrayList<>();
+
+ Iterator iterator = links.iterator();
+ while (iterator.hasNext()) {
+ byte[] data = iterator.next();
+ Core.RegisterLinkMessage registerMessage = Core.RegisterLinkMessage.parseFrom(data);
+ registerMessages.add(registerMessage);
+ iterator.remove();
+ if (!registerMessage.getAsync()) {
+ return registerMessages;
+ }
+ }
+
+ return registerMessages;
+ }
+
+}
diff --git a/src/main/java/org/listware/core/cmdb/Trigger.java b/src/main/java/org/listware/core/cmdb/Trigger.java
new file mode 100644
index 0000000..399ad3a
--- /dev/null
+++ b/src/main/java/org/listware/core/cmdb/Trigger.java
@@ -0,0 +1,209 @@
+/* Copyright 2022 Listware */
+
+package org.listware.core.cmdb;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.listware.core.documents.LinkDocument;
+import org.listware.core.documents.ObjectDocument;
+import org.listware.core.utils.exceptions.AlreadyTriggerException;
+import org.listware.core.utils.exceptions.TriggerNotFoundException;
+import org.listware.sdk.pbcmdb.Core;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class Trigger {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(Trigger.class);
+
+ private static String triggersKey = "triggers";
+
+ public static final String CREATE = "create";
+ public static final String UPDATE = "update";
+ public static final String DELETE = "delete";
+
+ public Trigger() {
+ // POJO
+ }
+
+ public Trigger(Core.Trigger trigger) {
+ this();
+ this.namespace = trigger.getFunctionType().getNamespace();
+ this.type = trigger.getFunctionType().getType();
+ }
+
+ @JsonProperty("namespace")
+ private String namespace;
+ @JsonProperty("type")
+ private String type;
+
+ /**
+ *
+ * @return The namespace
+ */
+ @JsonProperty("namespace")
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /**
+ *
+ * @return The type
+ */
+ @JsonProperty("type")
+ public String getType() {
+ return type;
+ }
+
+ public static Map getByType(ObjectDocument baseDocument, String type) throws Exception {
+ Map properties = baseDocument.getProperties();
+ if (!properties.containsKey(triggersKey)) {
+ throw new TriggerNotFoundException();
+ }
+ java.lang.Object object = properties.get(triggersKey);
+ Map> triggersMap = deserialize(object);
+
+ if (!triggersMap.containsKey(type)) {
+ throw new TriggerNotFoundException();
+ }
+
+ return triggersMap.get(type);
+ }
+
+ public static ObjectDocument add(ObjectDocument document, Core.Trigger trigger) throws Exception {
+ String key = trigger.getFunctionType().getNamespace() + "/" + trigger.getFunctionType().getType();
+
+ Map properties = document.getProperties();
+
+ Map> triggersMap;
+ if (properties.containsKey(triggersKey)) {
+ java.lang.Object object = properties.get(triggersKey);
+ triggersMap = deserialize(object);
+ } else {
+ triggersMap = new HashMap>();
+ }
+
+ Map triggers;
+ if (triggersMap.containsKey(trigger.getType())) {
+ triggers = triggersMap.get(trigger.getType());
+ } else {
+ triggers = new HashMap();
+ }
+
+ if (triggers.containsKey(key)) {
+ throw new AlreadyTriggerException();
+ }
+
+ triggers.put(key, new Trigger(trigger));
+
+ triggersMap.put(trigger.getType(), triggers);
+
+ properties.put(triggersKey, triggersMap);
+
+ document.updateProperties(properties);
+
+ return document;
+ }
+
+ public static LinkDocument add(LinkDocument document, Core.Trigger trigger) throws Exception {
+ String key = trigger.getFunctionType().getNamespace() + "/" + trigger.getFunctionType().getType();
+
+ Map properties = document.getProperties();
+
+ Map> triggersMap;
+ if (properties.containsKey(triggersKey)) {
+ java.lang.Object object = properties.get(triggersKey);
+ triggersMap = deserialize(object);
+ } else {
+ triggersMap = new HashMap>();
+ }
+
+ Map triggers;
+ if (triggersMap.containsKey(trigger.getType())) {
+ triggers = triggersMap.get(trigger.getType());
+ } else {
+ triggers = new HashMap();
+ }
+
+ if (triggers.containsKey(key)) {
+ throw new AlreadyTriggerException();
+ }
+
+ triggers.put(key, new Trigger(trigger));
+
+ triggersMap.put(trigger.getType(), triggers);
+
+ properties.put(triggersKey, triggersMap);
+
+ document.updateProperties(properties);
+
+ return document;
+ }
+
+ public static ObjectDocument delete(ObjectDocument document, Core.Trigger trigger) throws Exception {
+ Map properties = document.getProperties();
+ java.lang.Object object = properties.get(triggersKey);
+
+ // triggers map
+ Map> triggersMap = deserialize(object);
+
+ // type map
+ Map triggers = triggersMap.get(trigger.getType());
+
+ String key = trigger.getFunctionType().getNamespace() + "/" + trigger.getFunctionType().getType();
+
+ if (!triggers.containsKey(key)) {
+ return document;
+ }
+
+ triggers.remove(key);
+
+ triggersMap.put(trigger.getType(), triggers);
+
+ properties.put(triggersKey, triggersMap);
+
+ document.updateProperties(properties);
+ return document;
+ }
+
+ public static LinkDocument delete(LinkDocument document, Core.Trigger trigger) throws Exception {
+ Map properties = document.getProperties();
+ java.lang.Object object = properties.get(triggersKey);
+
+ // triggers map
+ Map> triggersMap = deserialize(object);
+
+ // type map
+ Map triggers = triggersMap.get(trigger.getType());
+
+ String key = trigger.getFunctionType().getNamespace() + "/" + trigger.getFunctionType().getType();
+
+ if (!triggers.containsKey(key)) {
+ return document;
+ }
+
+ triggers.remove(key);
+
+ triggersMap.put(trigger.getType(), triggers);
+
+ properties.put(triggersKey, triggersMap);
+
+ document.updateProperties(properties);
+ return document;
+ }
+
+ public static Map> deserialize(Object from) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
+
+ TypeReference