Repository: casbin/jcasbin (Java)

Issue:
[feature] support CLI usage for jCasbin (Casbin for Java)
For now, Casbin is mainly a library, or sometimes as a service. It also can be a CLI tool. So we can call jCasbin in shell.

At least, we need to support basic model, adapter, enforcer APIs this time: https://casbin.org/docs/model-storage, https://casbin.org/docs/policy-storage

Refer to:

- https://www.openpolicyagent.org/docs/latest/cli/
- https://docs.cerbos.dev/cerbos/latest/cli/index.html

Similar to:

- Go: https://github.com/casbin/casbin/issues/1414
- Python: https://github.com/casbin/pycasbin/issues/347


Discussion:
 @tangyang9464 @imp2002



Patch:
diff --git a/pom.xml b/pom.xml
index 82eb2120..7c030fbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -164,6 +164,27 @@
                     <check />
                 </configuration>
             </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.2.4</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>org.casbin.jcasbin.cli.Client</mainClass>
+                                </transformer>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
@@ -177,7 +198,7 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
             <version>${slf4j.version}</version>
-            <scope>test</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
@@ -234,6 +255,11 @@
             <artifactId>jackson-databind</artifactId>
             <version>2.16.1</version>
         </dependency>
+        <dependency>
+            <groupId>commons-cli</groupId>
+            <artifactId>commons-cli</artifactId>
+            <version>1.4</version>
+        </dependency>
 
     </dependencies>
 
diff --git a/src/main/java/org/casbin/jcasbin/cli/Client.java b/src/main/java/org/casbin/jcasbin/cli/Client.java
new file mode 100644
index 00000000..40cffc99
--- /dev/null
+++ b/src/main/java/org/casbin/jcasbin/cli/Client.java
@@ -0,0 +1,33 @@
+package org.casbin.jcasbin.cli;
+
+import org.apache.commons.cli.*;
+import org.casbin.jcasbin.main.Enforcer;
+
+public class Client {
+
+    public static void main(String[] args) {
+        try {
+            boolean res = clientEnforce(args);
+            System.out.println(res);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static boolean clientEnforce(String[] args) throws ParseException {
+        Options options = new Options();
+        Option model = new Option("m", "model", true, "the path of the model file");
+        options.addOption(model);
+        Option config = new Option("p", "policy", true, "the path of the policy file");
+        options.addOption(config);
+        Option enforceCMD = new Option("e", "enforce", true, "enforce");
+        options.addOption(enforceCMD);
+        CommandLineParser parser = new DefaultParser();
+        CommandLine cmd = parser.parse(options, args);
+        String modelPath = cmd.getOptionValue("model");
+        String policyFile = cmd.getOptionValue("policy");
+        Enforcer e = new Enforcer(modelPath, policyFile);
+        String enforce = cmd.getOptionValue("enforce");
+        return e.enforce(enforce.split(","));
+    }
+}


Test patch:
diff --git a/src/test/java/org/casbin/jcasbin/main/ClientTest.java b/src/test/java/org/casbin/jcasbin/main/ClientTest.java
new file mode 100644
index 00000000..97328de6
--- /dev/null
+++ b/src/test/java/org/casbin/jcasbin/main/ClientTest.java
@@ -0,0 +1,35 @@
+package org.casbin.jcasbin.main;
+
+import org.apache.commons.cli.ParseException;
+import org.casbin.jcasbin.cli.Client;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ClientTest {
+
+    @Test
+    public void testRBAC() throws ParseException {
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data1,read"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data1,write"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data2,read"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data2,write"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data1,read"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data1,write"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data2,read"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data2,write"}), true);
+    }
+
+    @Test
+    public void testABAC() throws ParseException {
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain1,data1,read"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain1,data1,write"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain2,data1,read"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain2,data1,write"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain1,data2,read"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain1,data2,write"}), false);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain2,data2,read"}), true);
+        assertEquals(Client.clientEnforce(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain2,data2,read"}), true);
+    }
+
+}