diff --git a/getting-started/developer-workflow/pom.xml b/getting-started/developer-workflow/pom.xml new file mode 100644 index 0000000..0a1d078 --- /dev/null +++ b/getting-started/developer-workflow/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + com.fluxtion.example + example.master + 1.0.0-SNAPSHOT + + + getting-started :: developer-workflow + developer-workflow + + + 21 + 21 + UTF-8 + + + + + com.google.guava + guava + 33.1.0-jre + + + org.junit.jupiter + junit-jupiter-api + 5.10.1 + test + + + + + + + com.fluxtion + fluxtion-maven-plugin + 3.0.14 + + + + scan + + + + + + + \ No newline at end of file diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/PermissionAotBuilder.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/PermissionAotBuilder.java new file mode 100644 index 0000000..bbbe6a5 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/PermissionAotBuilder.java @@ -0,0 +1,21 @@ +package com.fluxtion.example.devworkflow.aot; + +import com.fluxtion.compiler.EventProcessorConfig; +import com.fluxtion.compiler.FluxtionCompilerConfig; +import com.fluxtion.compiler.FluxtionGraphBuilder; +import com.fluxtion.example.devworkflow.integrating.CommandAuthorizerNode; +import com.fluxtion.example.devworkflow.integrating.CommandExecutor; + +public class PermissionAotBuilder implements FluxtionGraphBuilder { + + @Override + public void buildGraph(EventProcessorConfig eventProcessorConfig) { + eventProcessorConfig.addNode(new CommandExecutor(new CommandAuthorizerNode())); + } + + @Override + public void configureGeneration(FluxtionCompilerConfig compilerConfig) { + compilerConfig.setClassName("PermittedCommandProcessor"); + compilerConfig.setPackageName("com.fluxtion.example.devworkflow.aot.generated"); + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/generated/PermittedCommandProcessor.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/generated/PermittedCommandProcessor.java new file mode 100644 index 0000000..c2f4ce0 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/aot/generated/PermittedCommandProcessor.java @@ -0,0 +1,372 @@ +/* +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the Server Side Public License, version 1, +* as published by MongoDB, Inc. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* Server Side License for more details. +* +* You should have received a copy of the Server Side Public License +* along with this program. If not, see +* +. +*/ +package com.fluxtion.example.devworkflow.aot.generated; + +import com.fluxtion.runtime.StaticEventProcessor; +import com.fluxtion.runtime.lifecycle.BatchHandler; +import com.fluxtion.runtime.lifecycle.Lifecycle; +import com.fluxtion.runtime.EventProcessor; +import com.fluxtion.runtime.callback.InternalEventProcessor; +import com.fluxtion.example.devworkflow.integrating.AdminCommand; +import com.fluxtion.example.devworkflow.integrating.CommandAuthorizer; +import com.fluxtion.example.devworkflow.integrating.CommandAuthorizerNode; +import com.fluxtion.example.devworkflow.integrating.CommandExecutor; +import com.fluxtion.runtime.EventProcessorContext; +import com.fluxtion.runtime.audit.Auditor; +import com.fluxtion.runtime.audit.EventLogManager; +import com.fluxtion.runtime.audit.NodeNameAuditor; +import com.fluxtion.runtime.callback.CallbackDispatcherImpl; +import com.fluxtion.runtime.callback.ExportFunctionAuditEvent; +import com.fluxtion.runtime.event.Event; +import com.fluxtion.runtime.input.EventFeed; +import com.fluxtion.runtime.input.SubscriptionManagerNode; +import com.fluxtion.runtime.node.ForkedTriggerTask; +import com.fluxtion.runtime.node.MutableEventProcessorContext; +import com.fluxtion.runtime.time.Clock; +import com.fluxtion.runtime.time.ClockStrategy.ClockStrategyEvent; +import java.util.Map; + +import java.util.IdentityHashMap; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; + +/** + * + * + *
+ * generation time                 : Not available
+ * eventProcessorGenerator version : 9.2.23
+ * api version                     : 9.2.23
+ * 
+ * + * Event classes supported: + * + * + * + * @author Greg Higgins + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class PermittedCommandProcessor + implements EventProcessor, + StaticEventProcessor, + InternalEventProcessor, + BatchHandler, + Lifecycle, + CommandAuthorizer { + + //Node declarations + private final CallbackDispatcherImpl callbackDispatcher = new CallbackDispatcherImpl(); + private final CommandAuthorizerNode commandAuthorizerNode_1 = new CommandAuthorizerNode(); + private final CommandExecutor commandExecutor_0 = new CommandExecutor(commandAuthorizerNode_1); + public final NodeNameAuditor nodeNameLookup = new NodeNameAuditor(); + private final SubscriptionManagerNode subscriptionManager = new SubscriptionManagerNode(); + private final MutableEventProcessorContext context = + new MutableEventProcessorContext( + nodeNameLookup, callbackDispatcher, subscriptionManager, callbackDispatcher); + public final Clock clock = new Clock(); + private final ExportFunctionAuditEvent functionAudit = new ExportFunctionAuditEvent(); + //Dirty flags + private boolean initCalled = false; + private boolean processing = false; + private boolean buffering = false; + private final IdentityHashMap dirtyFlagSupplierMap = + new IdentityHashMap<>(0); + private final IdentityHashMap> dirtyFlagUpdateMap = + new IdentityHashMap<>(0); + + //Forked declarations + + //Filter constants + + public PermittedCommandProcessor(Map contextMap) { + context.replaceMappings(contextMap); + //node auditors + initialiseAuditor(clock); + initialiseAuditor(nodeNameLookup); + subscriptionManager.setSubscribingEventProcessor(this); + context.setEventProcessorCallback(this); + } + + public PermittedCommandProcessor() { + this(null); + } + + @Override + public void init() { + initCalled = true; + auditEvent(Lifecycle.LifecycleEvent.Init); + //initialise dirty lookup map + isDirty("test"); + clock.init(); + afterEvent(); + } + + @Override + public void start() { + if (!initCalled) { + throw new RuntimeException("init() must be called before start()"); + } + processing = true; + auditEvent(Lifecycle.LifecycleEvent.Start); + + afterEvent(); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + + @Override + public void stop() { + if (!initCalled) { + throw new RuntimeException("init() must be called before stop()"); + } + processing = true; + auditEvent(Lifecycle.LifecycleEvent.Stop); + + afterEvent(); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + + @Override + public void tearDown() { + initCalled = false; + auditEvent(Lifecycle.LifecycleEvent.TearDown); + nodeNameLookup.tearDown(); + clock.tearDown(); + subscriptionManager.tearDown(); + afterEvent(); + } + + @Override + public void setContextParameterMap(Map newContextMapping) { + context.replaceMappings(newContextMapping); + } + + @Override + public void addContextParameter(Object key, Object value) { + context.addMapping(key, value); + } + + //EVENT DISPATCH - START + @Override + public void onEvent(Object event) { + if (buffering) { + triggerCalculation(); + } + if (processing) { + callbackDispatcher.processReentrantEvent(event); + } else { + processing = true; + onEventInternal(event); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + } + + @Override + public void onEventInternal(Object event) { + if (event instanceof com.fluxtion.example.devworkflow.integrating.AdminCommand) { + AdminCommand typedEvent = (AdminCommand) event; + handleEvent(typedEvent); + } else if (event instanceof com.fluxtion.runtime.time.ClockStrategy.ClockStrategyEvent) { + ClockStrategyEvent typedEvent = (ClockStrategyEvent) event; + handleEvent(typedEvent); + } + } + + public void handleEvent(AdminCommand typedEvent) { + auditEvent(typedEvent); + //Default, no filter methods + commandExecutor_0.executeCommand(typedEvent); + afterEvent(); + } + + public void handleEvent(ClockStrategyEvent typedEvent) { + auditEvent(typedEvent); + //Default, no filter methods + clock.setClockStrategy(typedEvent); + afterEvent(); + } + //EVENT DISPATCH - END + + //EXPORTED SERVICE FUNCTIONS - START + @Override + public boolean authorize(com.fluxtion.example.devworkflow.integrating.CommandPermission arg0) { + beforeServiceCall( + "public boolean com.fluxtion.example.devworkflow.integrating.CommandAuthorizerNode.authorize(com.fluxtion.example.devworkflow.integrating.CommandPermission)"); + ExportFunctionAuditEvent typedEvent = functionAudit; + commandAuthorizerNode_1.authorize(arg0); + afterServiceCall(); + return true; + } + + @Override + public boolean removeAuthorized( + com.fluxtion.example.devworkflow.integrating.CommandPermission arg0) { + beforeServiceCall( + "public boolean com.fluxtion.example.devworkflow.integrating.CommandAuthorizerNode.removeAuthorized(com.fluxtion.example.devworkflow.integrating.CommandPermission)"); + ExportFunctionAuditEvent typedEvent = functionAudit; + commandAuthorizerNode_1.removeAuthorized(arg0); + afterServiceCall(); + return true; + } + //EXPORTED SERVICE FUNCTIONS - END + + public void bufferEvent(Object event) { + buffering = true; + if (event instanceof com.fluxtion.example.devworkflow.integrating.AdminCommand) { + AdminCommand typedEvent = (AdminCommand) event; + auditEvent(typedEvent); + commandExecutor_0.executeCommand(typedEvent); + } else if (event instanceof com.fluxtion.runtime.time.ClockStrategy.ClockStrategyEvent) { + ClockStrategyEvent typedEvent = (ClockStrategyEvent) event; + auditEvent(typedEvent); + clock.setClockStrategy(typedEvent); + } + } + + public void triggerCalculation() { + buffering = false; + String typedEvent = "No event information - buffered dispatch"; + afterEvent(); + } + + private void auditEvent(Object typedEvent) { + clock.eventReceived(typedEvent); + nodeNameLookup.eventReceived(typedEvent); + } + + private void auditEvent(Event typedEvent) { + clock.eventReceived(typedEvent); + nodeNameLookup.eventReceived(typedEvent); + } + + private void initialiseAuditor(Auditor auditor) { + auditor.init(); + auditor.nodeRegistered(commandAuthorizerNode_1, "commandAuthorizerNode_1"); + auditor.nodeRegistered(commandExecutor_0, "commandExecutor_0"); + auditor.nodeRegistered(callbackDispatcher, "callbackDispatcher"); + auditor.nodeRegistered(subscriptionManager, "subscriptionManager"); + auditor.nodeRegistered(context, "context"); + } + + private void beforeServiceCall(String functionDescription) { + functionAudit.setFunctionDescription(functionDescription); + auditEvent(functionAudit); + if (buffering) { + triggerCalculation(); + } + processing = true; + } + + private void afterServiceCall() { + afterEvent(); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + + private void afterEvent() { + + clock.processingComplete(); + nodeNameLookup.processingComplete(); + } + + @Override + public void batchPause() { + auditEvent(Lifecycle.LifecycleEvent.BatchPause); + processing = true; + + afterEvent(); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + + @Override + public void batchEnd() { + auditEvent(Lifecycle.LifecycleEvent.BatchEnd); + processing = true; + + afterEvent(); + callbackDispatcher.dispatchQueuedCallbacks(); + processing = false; + } + + @Override + public boolean isDirty(Object node) { + return dirtySupplier(node).getAsBoolean(); + } + + @Override + public BooleanSupplier dirtySupplier(Object node) { + if (dirtyFlagSupplierMap.isEmpty()) {} + + return dirtyFlagSupplierMap.getOrDefault(node, StaticEventProcessor.ALWAYS_FALSE); + } + + @Override + public void setDirty(Object node, boolean dirtyFlag) { + if (dirtyFlagUpdateMap.isEmpty()) {} + + dirtyFlagUpdateMap.get(node).accept(dirtyFlag); + } + + @Override + public T getNodeById(String id) throws NoSuchFieldException { + return nodeNameLookup.getInstanceById(id); + } + + @Override + public A getAuditorById(String id) + throws NoSuchFieldException, IllegalAccessException { + return (A) this.getClass().getField(id).get(this); + } + + @Override + public void addEventFeed(EventFeed eventProcessorFeed) { + subscriptionManager.addEventProcessorFeed(eventProcessorFeed); + } + + @Override + public void removeEventFeed(EventFeed eventProcessorFeed) { + subscriptionManager.removeEventProcessorFeed(eventProcessorFeed); + } + + @Override + public PermittedCommandProcessor newInstance() { + return new PermittedCommandProcessor(); + } + + @Override + public PermittedCommandProcessor newInstance(Map contextMap) { + return new PermittedCommandProcessor(); + } + + @Override + public String getLastAuditLogRecord() { + try { + EventLogManager eventLogManager = + (EventLogManager) this.getClass().getField(EventLogManager.NODE_NAME).get(this); + return eventLogManager.lastRecordAsString(); + } catch (Throwable e) { + return ""; + } + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/experiment/MainExperiment.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/experiment/MainExperiment.java new file mode 100644 index 0000000..df9c2a2 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/experiment/MainExperiment.java @@ -0,0 +1,100 @@ +package com.fluxtion.example.devworkflow.experiment; + +import com.fluxtion.compiler.Fluxtion; +import com.fluxtion.runtime.annotations.ExportService; +import com.fluxtion.runtime.annotations.NoTriggerReference; +import com.fluxtion.runtime.annotations.OnEventHandler; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import lombok.Data; + +public class MainExperiment { + public static void main(String[] args) { + var processor = Fluxtion.interpret(new CommandExecutor(new CommandAuthorizerNode())); + processor.init(); + + CommandAuthorizer commandAuthorizer = processor.getExportedService(); + commandAuthorizer.authorize(new CommandPermission("admin", "shutdown")); + commandAuthorizer.authorize(new CommandPermission("admin", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Aslam", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Puck", "createMischief")); + + commandAuthorizer.dumpMap(); + + processor.onEvent(new AdminCommand("admin", "shutdown", () -> System.out.println("executing shutdown command"))); + processor.onEvent(new AdminCommand("Aslam", "listUser", () -> System.out.println("executing listUser command"))); + processor.onEvent(new AdminCommand("Puck", "createMischief", () -> System.out.println("move the stool"))); + processor.onEvent(new AdminCommand("Aslam", "shutdown", () -> System.out.println("executing shutdown command"))); + + commandAuthorizer.removeAuthorized(new CommandPermission("Puck", "createMischief")); + commandAuthorizer.dumpMap(); + processor.onEvent(new AdminCommand("Puck", "createMischief", () -> System.out.println("move the stool"))); + } + + public interface CommandAuthorizer { + boolean authorize(CommandPermission commandPermission); + + boolean removeAuthorized(CommandPermission commandPermission); + + //used for testing + void dumpMap(); + } + + public static class CommandAuthorizerNode implements @ExportService CommandAuthorizer { + private transient final Multimap permissionMap = HashMultimap.create(); + + @Override + public boolean authorize(CommandPermission commandPermission) { + permissionMap.put(commandPermission.user, commandPermission.command); + return false; + } + + @Override + public boolean removeAuthorized(CommandPermission commandPermission) { + permissionMap.remove(commandPermission.user, commandPermission.command); + return false; + } + + @Override + public void dumpMap() { + System.out.println(""" + + Permission map + -------------------- + %s + -------------------- + """.formatted(permissionMap.toString())); + } + + boolean isAuthorized(AdminCommand adminCommand) { + return permissionMap.containsEntry(adminCommand.user, adminCommand.command); + } + } + + @Data + public static class CommandExecutor { + @NoTriggerReference + private final CommandAuthorizerNode commandAuthorizer; + + @OnEventHandler + public boolean executeCommand(AdminCommand command) { + boolean authorized = commandAuthorizer.isAuthorized(command); + if (authorized) { + System.out.println("Executing command " + command); + command.commandToExecute().run(); + } else { + System.out.println("FAILED authorization for command " + command); + } + return authorized; + } + } + + public record CommandPermission(String user, String command) { } + + public record AdminCommand(String user, String command, Runnable commandToExecute) { + @Override + public String toString() { + return "AdminCommand{user='" + user + '\'' + ", command='" + command + '\'' +'}'; + } + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/AdminCommand.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/AdminCommand.java new file mode 100644 index 0000000..40eb836 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/AdminCommand.java @@ -0,0 +1,12 @@ +package com.fluxtion.example.devworkflow.integrating; + +public record AdminCommand(String user, String command, Runnable commandToExecute) { + + @Override + public String toString() { + return "AdminCommand{" + + "user='" + user + '\'' + + ", command='" + command + '\'' + + '}'; + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizer.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizer.java new file mode 100644 index 0000000..595e336 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizer.java @@ -0,0 +1,7 @@ +package com.fluxtion.example.devworkflow.integrating; + +public interface CommandAuthorizer { + boolean authorize(CommandPermission commandPermission); + + boolean removeAuthorized(CommandPermission commandPermission); +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizerNode.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizerNode.java new file mode 100644 index 0000000..4129c7c --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandAuthorizerNode.java @@ -0,0 +1,25 @@ +package com.fluxtion.example.devworkflow.integrating; + +import com.fluxtion.runtime.annotations.ExportService; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +public class CommandAuthorizerNode implements @ExportService CommandAuthorizer { + private transient final Multimap permissionMap = HashMultimap.create(); + + @Override + public boolean authorize(CommandPermission commandPermission) { + permissionMap.put(commandPermission.user(), commandPermission.command()); + return false; + } + + @Override + public boolean removeAuthorized(CommandPermission commandPermission) { + permissionMap.remove(commandPermission.user(), commandPermission.command()); + return false; + } + + boolean isAuthorized(AdminCommand adminCommand) { + return permissionMap.containsEntry(adminCommand.user(), adminCommand.command()); + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandExecutor.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandExecutor.java new file mode 100644 index 0000000..2e2ba36 --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandExecutor.java @@ -0,0 +1,20 @@ +package com.fluxtion.example.devworkflow.integrating; + +import com.fluxtion.runtime.annotations.NoTriggerReference; +import com.fluxtion.runtime.annotations.OnEventHandler; +import lombok.Data; + +@Data +public class CommandExecutor { + @NoTriggerReference + private final CommandAuthorizerNode commandAuthorizer; + + @OnEventHandler + public boolean executeCommand(AdminCommand command) { + boolean authorized = commandAuthorizer.isAuthorized(command); + if (authorized) { + command.commandToExecute().run(); + } + return authorized; + } +} diff --git a/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandPermission.java b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandPermission.java new file mode 100644 index 0000000..acf616b --- /dev/null +++ b/getting-started/developer-workflow/src/main/java/com/fluxtion/example/devworkflow/integrating/CommandPermission.java @@ -0,0 +1,4 @@ +package com.fluxtion.example.devworkflow.integrating; + +public record CommandPermission(String user, String command) { +} diff --git a/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/aot/CommandExecutorTest.java b/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/aot/CommandExecutorTest.java new file mode 100644 index 0000000..83d4faf --- /dev/null +++ b/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/aot/CommandExecutorTest.java @@ -0,0 +1,40 @@ +package com.fluxtion.example.devworkflow.aot; + +import com.fluxtion.example.devworkflow.aot.generated.PermittedCommandProcessor; +import com.fluxtion.example.devworkflow.integrating.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.atomic.LongAdder; + +class CommandExecutorTest { + + @Test + public void testPermission(){ + var processor = new PermittedCommandProcessor(); + processor.init(); + + CommandAuthorizer commandAuthorizer = processor.getExportedService(); + commandAuthorizer.authorize(new CommandPermission("admin", "shutdown")); + commandAuthorizer.authorize(new CommandPermission("admin", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Aslam", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Puck", "createMischief")); + + LongAdder longAdder = new LongAdder(); + processor.onEvent(new AdminCommand("admin", "shutdown", longAdder::increment)); + Assertions.assertEquals(1, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Aslam", "listUser", longAdder::increment)); + Assertions.assertEquals(2, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Puck", "createMischief", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Aslam", "shutdown", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + + commandAuthorizer.removeAuthorized(new CommandPermission("Puck", "createMischief")); + processor.onEvent(new AdminCommand("Puck", "createMischief", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + } +} \ No newline at end of file diff --git a/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/integrating/CommandExecutorTest.java b/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/integrating/CommandExecutorTest.java new file mode 100644 index 0000000..828c48a --- /dev/null +++ b/getting-started/developer-workflow/src/test/java/com/fluxtion/example/devworkflow/integrating/CommandExecutorTest.java @@ -0,0 +1,39 @@ +package com.fluxtion.example.devworkflow.integrating; + +import com.fluxtion.compiler.Fluxtion; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.atomic.LongAdder; + +class CommandExecutorTest { + + @Test + public void testPermission(){ + var processor = Fluxtion.interpret(new CommandExecutor(new CommandAuthorizerNode())); + processor.init(); + + CommandAuthorizer commandAuthorizer = processor.getExportedService(); + commandAuthorizer.authorize(new CommandPermission("admin", "shutdown")); + commandAuthorizer.authorize(new CommandPermission("admin", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Aslam", "listUser")); + commandAuthorizer.authorize(new CommandPermission("Puck", "createMischief")); + + LongAdder longAdder = new LongAdder(); + processor.onEvent(new AdminCommand("admin", "shutdown", longAdder::increment)); + Assertions.assertEquals(1, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Aslam", "listUser", longAdder::increment)); + Assertions.assertEquals(2, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Puck", "createMischief", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + + processor.onEvent(new AdminCommand("Aslam", "shutdown", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + + commandAuthorizer.removeAuthorized(new CommandPermission("Puck", "createMischief")); + processor.onEvent(new AdminCommand("Puck", "createMischief", longAdder::increment)); + Assertions.assertEquals(3, longAdder.intValue()); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2efb96f..d061c47 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ along with this program. If not, see getting-started/tutorial6-lottery-nospring reference-examples service-helloworld + getting-started/developer-workflow