Merge pull request #1 from apache/SLING-7227

SLING-7227:  Add ability to register custom privileges.
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/OperationVisitor.java b/src/main/java/org/apache/sling/repoinit/parser/operations/OperationVisitor.java
index 33e9a77..8488b2c 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/OperationVisitor.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/OperationVisitor.java
@@ -27,5 +27,6 @@
     void visitCreatePath(CreatePath cp);
     void visitRegisterNamespace(RegisterNamespace rn);
     void visitRegisterNodetypes(RegisterNodetypes b);
+    void visitRegisterPrivilege(RegisterPrivilege rp);
     void visitDisableServiceUser(DisableServiceUser dsu);
 }
diff --git a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterPrivilege.java b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterPrivilege.java
new file mode 100644
index 0000000..422b8fe
--- /dev/null
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterPrivilege.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.repoinit.parser.operations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class RegisterPrivilege extends Operation {
+
+    private final String privilegeName;
+    private final boolean isAbstract;
+
+    public String getPrivilegeName() {
+        return privilegeName;
+    }
+
+    public boolean isAbstract() {
+        return isAbstract;
+    }
+
+    public List<String> getDeclaredAggregateNames() {
+        return declaredAggregateNames;
+    }
+
+    private final List<String> declaredAggregateNames;
+
+    public RegisterPrivilege(String privilegeName, boolean isAbstract, List<String> declaredAggregateNames) {
+        this.privilegeName = privilegeName;
+        this.isAbstract = isAbstract;
+        this.declaredAggregateNames = Collections.unmodifiableList(new ArrayList<>(declaredAggregateNames));
+    }
+
+    @Override
+    public void accept(OperationVisitor v) {
+        v.visitRegisterPrivilege(this);
+    }
+
+    @Override
+    protected String getParametersDescription() {
+        return this.privilegeName + "," + this.isAbstract + "," + this.declaredAggregateNames;
+    }
+
+    public String toString() {
+        StringBuilder builder = new StringBuilder("register ");
+        if (this.isAbstract) {
+            builder.append("abstract ");
+        }
+        builder.append("privilege ");
+        builder.append(this.privilegeName);
+
+        if (!this.declaredAggregateNames.isEmpty()) {
+            builder.append(" with ");
+            Iterator<String> iter = this.declaredAggregateNames.iterator();
+            builder.append(iter.next());
+            while (iter.hasNext()) {
+                builder.append(',').append(iter.next());
+            }
+        }
+
+        return builder.toString();
+    }
+}
diff --git a/src/main/javacc/RepoInitGrammar.jjt b/src/main/javacc/RepoInitGrammar.jjt
index 7c2215f..af1ab56 100644
--- a/src/main/javacc/RepoInitGrammar.jjt
+++ b/src/main/javacc/RepoInitGrammar.jjt
@@ -73,7 +73,9 @@
 |   < NODETYPES: "nodetypes" >
 |   < REGISTER: "register" >
 |   < NAMESPACE: "namespace" >
+|   < PRIVILEGE: "privilege" >
 |   < WITH: "with" >
+|   < ABSTRACT: "abstract" >
 |   < PASSWORD: "password" >
 |   < START_TEXTBLOCK: "<<===" > : TEXTBLOCK
 |   < LPAREN: "(" >
@@ -132,6 +134,7 @@
         | createPathStatement(result)
         | registerNamespaceStatement(result)
         | registerNodetypesStatement(result)
+        | registerPrivilegeStatement(result)
         | createUserStatement(result)
         | deleteUserStatement(result)
         | disableServiceUserStatement(result)
@@ -480,6 +483,20 @@
     (<EOL> | <EOF>)
 }
 
+void registerPrivilegeStatement(List<Operation> result) :
+{
+    Token privilege;
+    boolean isAbstract = false;
+    List<String> aggregates = new ArrayList<String>();
+}
+{
+    <REGISTER> ((<ABSTRACT>) {isAbstract = true;})? <PRIVILEGE> privilege = <STRING>  (<WITH> aggregates = principalsList())?
+    {
+        result.add(new RegisterPrivilege(privilege.image, isAbstract, aggregates));
+    }
+    (<EOL> | <EOF>)
+}
+
 void textBlock(StringBuilder b) : 
 {
     Token t;
diff --git a/src/test/java/org/apache/sling/repoinit/parser/test/OperationToStringVisitor.java b/src/test/java/org/apache/sling/repoinit/parser/test/OperationToStringVisitor.java
index 4de269c..07e8dfb 100644
--- a/src/test/java/org/apache/sling/repoinit/parser/test/OperationToStringVisitor.java
+++ b/src/test/java/org/apache/sling/repoinit/parser/test/OperationToStringVisitor.java
@@ -31,6 +31,7 @@
 import org.apache.sling.repoinit.parser.operations.RegisterNodetypes;
 import org.apache.sling.repoinit.parser.operations.OperationVisitor;
 import org.apache.sling.repoinit.parser.operations.RegisterNamespace;
+import org.apache.sling.repoinit.parser.operations.RegisterPrivilege;
 import org.apache.sling.repoinit.parser.operations.SetAclPaths;
 import org.apache.sling.repoinit.parser.operations.SetAclPrincipals;
 
@@ -119,6 +120,11 @@
     }
 
     @Override
+    public void visitRegisterPrivilege(RegisterPrivilege rp) {
+        out.println(rp.toString());
+    }
+
+    @Override
     public void visitDisableServiceUser(DisableServiceUser dsu) {
         out.println(dsu.toString());
     }
diff --git a/src/test/resources/testcases/test-42-output.txt b/src/test/resources/testcases/test-42-output.txt
new file mode 100644
index 0000000..3fc8e0c
--- /dev/null
+++ b/src/test/resources/testcases/test-42-output.txt
@@ -0,0 +1,6 @@
+register privilege withoutabstract_withoutaggregates
+register abstract privilege withabstract_withoutaggregates
+register privilege withoutabstract_withaggregate with bla
+register privilege withoutabstract_withaggregates with bla,blub
+register abstract privilege withabstract_withaggregate with foo
+register abstract privilege withabstract_withaggregates with foo,bar
\ No newline at end of file
diff --git a/src/test/resources/testcases/test-42.txt b/src/test/resources/testcases/test-42.txt
new file mode 100644
index 0000000..3fc8e0c
--- /dev/null
+++ b/src/test/resources/testcases/test-42.txt
@@ -0,0 +1,6 @@
+register privilege withoutabstract_withoutaggregates
+register abstract privilege withabstract_withoutaggregates
+register privilege withoutabstract_withaggregate with bla
+register privilege withoutabstract_withaggregates with bla,blub
+register abstract privilege withabstract_withaggregate with foo
+register abstract privilege withabstract_withaggregates with foo,bar
\ No newline at end of file
diff --git a/src/test/resources/testcases/test-99-output.txt b/src/test/resources/testcases/test-99-output.txt
index 9cbe34e..13a435d 100644
--- a/src/test/resources/testcases/test-99-output.txt
+++ b/src/test/resources/testcases/test-99-output.txt
@@ -31,6 +31,10 @@
  [slingevent:Event] > nt:unstructured, nt:hierarchyNode
       - slingevent:topic (string)
       - slingevent:properties (binary)
+register privilege priv
+register abstract privilege abstract_priv
+register privilege priv with declared_aggregate_priv
+register privilege priv with declared_aggregate_priv1,declared_aggregate_priv2
 CreateUser userE (with encoded password), password=afdgwdsdf, passwordEncoding=someEncoding
 CreateUser one_with-more-chars.ok:/123456 (with encoded password), password=pw-with.ok-:/13456, passwordEncoding=encoding_with.ok-:/12345
 CreateUser userF with path /for/userF
diff --git a/src/test/resources/testcases/test-99.txt b/src/test/resources/testcases/test-99.txt
index df3d15d..5b1fada 100644
--- a/src/test/resources/testcases/test-99.txt
+++ b/src/test/resources/testcases/test-99.txt
@@ -63,6 +63,11 @@
       - slingevent:properties (binary)
 ===>>
 
+register privilege priv
+register abstract privilege abstract_priv
+register privilege priv with declared_aggregate_priv
+register privilege priv with declared_aggregate_priv1,declared_aggregate_priv2
+
 create user userE with password {someEncoding} afdgwdsdf
 create user one_with-more-chars.ok:/123456 with password {encoding_with.ok-:/12345} pw-with.ok-:/13456
 create user userF with path /for/userF