This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-repoinit-parser.git
The following commit(s) were added to refs/heads/master by this push:
new 94c95ab SLING-10236 : Introduce Operation.asRepoInitString (#9)
94c95ab is described below
commit 94c95ab7939064176045d7bcc1f582c7d212f34b
Author: anchela <[email protected]>
AuthorDate: Tue Mar 30 15:13:36 2021 +0200
SLING-10236 : Introduce Operation.asRepoInitString (#9)
* SLING-10236 : Introduce Operation.asRepoInitString (initial draft with
FIXMEs and TODOs)
* SLING-10236 : Introduce Operation.asRepoInitString (rename escape method,
add additional assertion in test assuming that Operation.toString is suitable
to compare expected and generated result)
* SLING-10236 : Introduce Operation.asRepoInitString (wip)
* SLING-10236 : Introduce Operation.asRepoInitString (missing notnull
annotations)
* SLING-10236 : Introduce Operation.asRepoInitString (verbose output for
repoinitparseexception in tests)
* SLING-10236 : Introduce Operation.asRepoInitString (incorporate
SLING-10192, thanks Karl for spotting)
* SLING-10236 : Introduce Operation.asRepoInitString (move AsRepoInitTest
such that Operation.getParameterDescription is accessible to the test)
* SLING-10236 - clarify the test's purpose
* SLING-10236 - refactor AsRepoInitTest to reuse the ParserTest logic
* SLING-10236 - use Action.toString()
Co-authored-by: angela <[email protected]>
Co-authored-by: Bertrand Delacretaz <[email protected]>
---
pom.xml | 6 ++
.../repoinit/parser/operations/AclGroupBase.java | 61 +++++++++++++++++++
.../parser/operations/AddGroupMembers.java | 7 +++
.../repoinit/parser/operations/CreateGroup.java | 7 +++
.../repoinit/parser/operations/CreatePath.java | 27 ++++++++-
.../parser/operations/CreateServiceUser.java | 7 +++
.../repoinit/parser/operations/CreateUser.java | 23 +++++++
.../repoinit/parser/operations/DeleteGroup.java | 7 +++
.../parser/operations/DeleteServiceUser.java | 7 +++
.../repoinit/parser/operations/DeleteUser.java | 7 +++
.../parser/operations/DisableServiceUser.java | 9 ++-
.../repoinit/parser/operations/Operation.java | 41 ++++++++++++-
.../operations/OperationWithPathOptions.java | 12 ++++
.../parser/operations/PathSegmentDefinition.java | 24 ++++++--
.../parser/operations/RegisterNamespace.java | 7 +++
.../parser/operations/RegisterNodetypes.java | 41 ++++++++++++-
.../parser/operations/RegisterPrivilege.java | 7 +++
.../parser/operations/RemoveGroupMembers.java | 7 +++
.../repoinit/parser/operations/SetAclPaths.java | 12 +++-
.../parser/operations/SetAclPrincipalBased.java | 10 +++-
.../parser/operations/SetAclPrincipals.java | 18 +++++-
.../repoinit/parser/operations/SetProperties.java | 44 ++++++++++++++
.../repoinit/parser/operations/AsRepoInitTest.java | 70 ++++++++++++++++++++++
.../sling/repoinit/parser/test/ParserTest.java | 63 ++++++++++---------
24 files changed, 484 insertions(+), 40 deletions(-)
diff --git a/pom.xml b/pom.xml
index 0d78786..465267c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,12 @@
<version>2.20.0</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ <version>18.0.0</version>
+ <scope>provided</scope>
+ </dependency>
<!-- testing -->
<dependency>
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
index 9bc5861..12e02a3 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/AclGroupBase.java
@@ -20,8 +20,11 @@ package org.apache.sling.repoinit.parser.operations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Formatter;
import java.util.List;
+import org.apache.sling.repoinit.parser.operations.AclLine.Action;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
/** Base class for operations that group AclLines */
@@ -59,4 +62,62 @@ abstract class AclGroupBase extends Operation {
public List<String> getOptions() {
return aclOptions;
}
+
+ String asRepoInit(@NotNull String topLine, boolean hasPathLines) {
+ try (Formatter formatter = new Formatter()) {
+ formatter.format("%s",topLine);
+ for (AclLine line : lines) {
+ String action = actionToString(line.getAction());
+ String privileges = privilegesToString(line.getAction(),
line.getProperty(AclLine.PROP_PRIVILEGES));
+ String onOrFor;
+ if (hasPathLines) {
+ String pathStr =
pathsToString(line.getProperty(AclLine.PROP_PATHS));
+ onOrFor = (pathStr.isEmpty()) ? "" : " on " + pathStr;
+ } else {
+ onOrFor = " for " +
listToString(line.getProperty(AclLine.PROP_PRINCIPALS));
+ }
+ formatter.format(" %s %s%s%s%s%n", action, privileges,
onOrFor,
+
nodetypesToString(line.getProperty(AclLine.PROP_NODETYPES)),
+ restrictionsToString(line.getRestrictions()));
+ }
+ formatter.format("end%n");
+ return formatter.toString();
+ }
+ }
+
+ @NotNull
+ String getAclOptionsString() {
+ return (aclOptions.isEmpty()) ? "" : " (ACLOptions="+
listToString(aclOptions)+")";
+ }
+
+ @NotNull
+ static String privilegesToString(@NotNull AclLine.Action action, @NotNull
List<String> privileges) {
+ return (action == AclLine.Action.REMOVE_ALL) ? "*" :
listToString(privileges);
+ }
+
+ @NotNull
+ private static String nodetypesToString(@NotNull List<String> nodetypes) {
+ return (nodetypes.isEmpty()) ? "" : " nodetypes " +
listToString(nodetypes);
+ }
+
+ @NotNull
+ private static String restrictionsToString(@NotNull
List<RestrictionClause> restrictionClauses) {
+ StringBuilder sb = new StringBuilder();
+ for (RestrictionClause rc : restrictionClauses) {
+ sb.append(" restriction(").append(rc.getName());
+ for (String v : rc.getValues()) {
+ sb.append(",").append(v);
+ }
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+
+ @NotNull
+ private static String actionToString(@NotNull AclLine.Action action) {
+ if(action.equals(Action.REMOVE_ALL)) {
+ return Action.REMOVE.toString().toLowerCase();
+ }
+ return action.toString().toLowerCase();
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
index 89aa5ac..5ccb49f 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/AddGroupMembers.java
@@ -19,6 +19,7 @@ package org.apache.sling.repoinit.parser.operations;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -51,6 +52,12 @@ public class AddGroupMembers extends Operation {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("add %s to group %s%n", listToString(members),
groupname);
+ }
+
public String getGroupname() {
return groupname;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
index 34a594b..3384c46 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateGroup.java
@@ -18,6 +18,7 @@
package org.apache.sling.repoinit.parser.operations;
import org.apache.sling.repoinit.parser.impl.WithPathOptions;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -59,6 +60,12 @@ public class CreateGroup extends OperationWithPathOptions {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return asRepoInitString("group", groupname);
+ }
+
public String getGroupname() {
return groupname;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java
index 4b66144..0a68ef9 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/CreatePath.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -43,6 +44,28 @@ public class CreatePath extends Operation {
return pathDef.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ String defaultTypeStr = (defaultPrimaryType == null) ? "" :
"("+defaultPrimaryType+") ";
+ StringBuilder sb = new StringBuilder();
+ for (PathSegmentDefinition psd : getDefinitions()) {
+ sb.append("/").append(psd.getSegment());
+ List<String> mixins = psd.getMixins();
+ if (!psd.isDefaultPrimary() || !mixins.isEmpty()) {
+ sb.append("(");
+ if (!psd.isDefaultPrimary()) {
+ sb.append(psd.getPrimaryType());
+ }
+ if (!mixins.isEmpty()) {
+ sb.append(" mixin ").append(listToString(mixins));
+ }
+ sb.append(")");
+ }
+ }
+ return String.format("create path %s%s%n", defaultTypeStr,
sb.toString());
+ }
+
@Override
public void accept(OperationVisitor v) {
v.visitCreatePath(this);
@@ -62,16 +85,18 @@ public class CreatePath extends Operation {
continue;
}
String pt = defaultPrimaryType;
+ boolean isDefaultPrimary = true;
List<String> ms = null;
if(i == segments.length -1) {
if (primaryType != null) {
pt = primaryType;
+ isDefaultPrimary = false;
}
if (mixins != null && ! mixins.isEmpty()) {
ms = mixins;
}
}
- pathDef.add(new PathSegmentDefinition(segments[i], pt, ms));
+ pathDef.add(new PathSegmentDefinition(segments[i], pt, ms,
isDefaultPrimary));
}
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateServiceUser.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateServiceUser.java
index e6b7611..ade4d12 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateServiceUser.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateServiceUser.java
@@ -18,6 +18,7 @@
package org.apache.sling.repoinit.parser.operations;
import org.apache.sling.repoinit.parser.impl.WithPathOptions;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -48,4 +49,10 @@ public class CreateServiceUser extends ServiceUserOperation {
return sb.toString();
}
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return asRepoInitString("service user", username);
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateUser.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateUser.java
index 7d18b1b..827cdf5 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/CreateUser.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/CreateUser.java
@@ -18,6 +18,7 @@
package org.apache.sling.repoinit.parser.operations;
import org.apache.sling.repoinit.parser.impl.WithPathOptions;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -70,6 +71,28 @@ public class CreateUser extends OperationWithPathOptions {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ String path = getPath();
+ if (path == null || path.isEmpty()) {
+ return String.format("create user %s%s%n", username,
getPwString());
+ } else {
+ String forced = (isForcedPath()) ? "forced " : "";
+ return String.format("create user %s with %spath %s%s%n",
username, forced, path, getPwString());
+ }
+ }
+
+ @NotNull
+ private String getPwString() {
+ if (password == null || password.isEmpty()) {
+ return "";
+ } else {
+ String enc = (passwordEncoding != null) ? "{"+passwordEncoding+"}
" : "";
+ return String.format(" with password %s%s", enc, password);
+ }
+ }
+
public String getUsername() {
return username;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
index 0d10651..1fcb807 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteGroup.java
@@ -17,6 +17,7 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -42,6 +43,12 @@ public class DeleteGroup extends Operation {
return groupname;
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("delete group %s%n", groupname);
+ }
+
public String getGroupname() {
return groupname;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteServiceUser.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteServiceUser.java
index 91d0061..359653d 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteServiceUser.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteServiceUser.java
@@ -17,6 +17,7 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -29,4 +30,10 @@ public class DeleteServiceUser extends ServiceUserOperation {
public void accept(OperationVisitor v) {
v.visitDeleteServiceUser(this);
}
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("delete service user %s%n", username);
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteUser.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteUser.java
index f0934d0..7f85d18 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteUser.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/DeleteUser.java
@@ -17,6 +17,7 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -40,6 +41,12 @@ public class DeleteUser extends Operation {
return username;
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("delete user %s%n", username);
+ }
+
public String getUsername() {
return username;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/DisableServiceUser.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/DisableServiceUser.java
index 6e4a393..433a041 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/DisableServiceUser.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/DisableServiceUser.java
@@ -17,6 +17,7 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -41,7 +42,13 @@ public class DisableServiceUser extends ServiceUserOperation
{
}
return sb.toString();
}
-
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("disable service user %s : %s%n", username,
escapeQuotes(reason));
+ }
+
@Override
public void accept(OperationVisitor v) {
v.visitDisableServiceUser(this);
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
index bf6581e..e1b1d80 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/Operation.java
@@ -17,15 +17,22 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
+import java.util.List;
+import java.util.stream.Collectors;
+
@ProviderType
public abstract class Operation {
public abstract void accept(OperationVisitor v);
public static final String DQUOTE = "\"";
protected abstract String getParametersDescription();
-
+
+ @NotNull
+ public abstract String asRepoInitString();
+
@Override
public String toString() {
return getClass().getSimpleName() + " " + getParametersDescription();
@@ -41,4 +48,36 @@ public abstract class Operation {
}
return s;
}
+
+ @NotNull
+ static String escapeQuotes(@NotNull String s) {
+ String esc = s.replace("\\", "\\\\");
+ String escapequotes = esc.replace("\"", "\\\"");
+ return "\"" + escapequotes + "\"";
+ }
+
+ @NotNull
+ static String listToString(@NotNull List<String> list) {
+ if (list.isEmpty()) {
+ return "";
+ } else {
+ return String.join(",", list);
+ }
+ }
+
+ @NotNull
+ static String pathsToString(@NotNull List<String> paths) {
+ return listToString(paths.stream()
+ .map(s -> {
+ if (s.startsWith(":") && s.contains("#")) {
+ String func = s.substring(1, s.indexOf(":",1));
+ String s2 = s.substring(func.length()+2,
s.lastIndexOf('#'));
+ String trailingPath = (s.endsWith("#")) ? "" :
s.substring(s.indexOf("#")+1);
+ return func + "(" + s2 +")" + trailingPath;
+ } else {
+ return s;
+ }
+ })
+ .collect(Collectors.toList()));
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/OperationWithPathOptions.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/OperationWithPathOptions.java
index 79c00b8..a4f1f65 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/OperationWithPathOptions.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/OperationWithPathOptions.java
@@ -18,6 +18,7 @@
package org.apache.sling.repoinit.parser.operations;
import org.apache.sling.repoinit.parser.impl.WithPathOptions;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -35,4 +36,15 @@ abstract class OperationWithPathOptions extends Operation {
public boolean isForcedPath() {
return wpopt.forcedPath;
}
+
+ @NotNull
+ String asRepoInitString(@NotNull String type, @NotNull String name) {
+ String path = wpopt.path;
+ if (path == null || path.isEmpty()) {
+ return String.format("create %s %s%n", type, name);
+ } else {
+ String forced = (wpopt.forcedPath) ? "forced " : "";
+ return String.format("create %s %s with %spath %s%n", type, name,
forced, path);
+ }
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java
index 96ce656..327156a 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/PathSegmentDefinition.java
@@ -17,8 +17,10 @@
package org.apache.sling.repoinit.parser.operations;
+import java.util.Collections;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
/** Defines a segment of a path to be created,
@@ -29,22 +31,32 @@ public class PathSegmentDefinition {
private final String segment;
private final String primaryType;
private final List<String> mixins;
-
+ private final boolean isDefaultPrimary;
+
public PathSegmentDefinition(String segment, String primaryType) {
- this(segment, primaryType, null);
+ this(segment, primaryType, null, false);
}
public PathSegmentDefinition(String segment, String primaryType,
List<String> mixins) {
+ this(segment, primaryType, mixins, false);
+ }
+
+ public PathSegmentDefinition(String segment, String primaryType, boolean
isDefaultPrimary) {
+ this(segment, primaryType, null, isDefaultPrimary);
+ }
+
+ public PathSegmentDefinition(String segment, String primaryType,
List<String> mixins, boolean isDefaultPrimary) {
this.segment = segment;
this.primaryType = primaryType;
- this.mixins = mixins;
+ this.mixins = (mixins == null) ? Collections.emptyList() : mixins;
+ this.isDefaultPrimary = isDefaultPrimary;
}
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(segment);
boolean hasPrimaryType = primaryType != null;
- boolean hasMixin = mixins != null && ! mixins.isEmpty();
+ boolean hasMixin = !mixins.isEmpty();
if (hasPrimaryType || hasMixin) {
sb.append("(");
if (hasPrimaryType) {
@@ -73,4 +85,8 @@ public class PathSegmentDefinition {
public List<String> getMixins() {
return mixins;
}
+
+ public boolean isDefaultPrimary() {
+ return isDefaultPrimary;
+ }
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNamespace.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNamespace.java
index 5d8f0dc..9ba2c99 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNamespace.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNamespace.java
@@ -17,6 +17,7 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -42,6 +43,12 @@ public class RegisterNamespace extends Operation {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("register namespace ( %s ) %s%n", prefix, uri);
+ }
+
@Override
public void accept(OperationVisitor v) {
v.visitRegisterNamespace(this);
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNodetypes.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNodetypes.java
index fa43c5e..2a34489 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNodetypes.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterNodetypes.java
@@ -17,8 +17,16 @@
package org.apache.sling.repoinit.parser.operations;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+
/** An embedded block of text */
@ProviderType
public class RegisterNodetypes extends Operation {
@@ -46,7 +54,38 @@ public class RegisterNodetypes extends Operation {
sb.append(getCndStatements());
return sb.toString();
}
-
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ try (Formatter formatter = new Formatter()) {
+ for (String nodetypeRegistrationSentence :
generateRepoInitLines(new BufferedReader(new StringReader(cndStatements)))) {
+ formatter.format("%s%n", nodetypeRegistrationSentence);
+ }
+ return formatter.toString();
+ } catch (IOException e) {
+ throw new RuntimeException("Unexpected IOException", e);
+ }
+ }
+
+ @NotNull
+ public static List<String> generateRepoInitLines(@NotNull BufferedReader
rawLines) throws IOException {
+ List<String> lines = new ArrayList<>();
+ lines.add("register nodetypes");
+ lines.add("<<===");
+
+ String raw;
+ while((raw = rawLines.readLine()) != null) {
+ if (raw.isEmpty()) {
+ lines.add("");
+ } else {
+ lines.add("<< "+raw);
+ }
+ }
+ lines.add("===>>");
+ return lines;
+ }
+
@Override
public void accept(OperationVisitor v) {
v.visitRegisterNodetypes(this);
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
index 3b62f87..c5e49f5 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterPrivilege.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/RegisterPrivilege.java
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -59,6 +60,12 @@ public class RegisterPrivilege extends Operation {
return this.privilegeName + "," + this.isAbstract + "," +
this.declaredAggregateNames;
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("%s%n", toString());
+ }
+
public String toString() {
StringBuilder builder = new StringBuilder("register ");
if (this.isAbstract) {
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
index ecd28c2..320e647 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/RemoveGroupMembers.java
@@ -19,6 +19,7 @@ package org.apache.sling.repoinit.parser.operations;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -51,6 +52,12 @@ public class RemoveGroupMembers extends Operation {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ return String.format("remove %s from group %s%n",
listToString(members), groupname);
+ }
+
public String getGroupname() {
return groupname;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
index 4b60953..e43aed7 100644
--- a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
+++ b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPaths.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
/** Set ACL statement that groups a set of AclLines
@@ -32,7 +33,7 @@ public class SetAclPaths extends AclGroupBase {
private final List<String> paths;
public SetAclPaths(List<String> paths, List<AclLine> lines) {
- this(paths,lines,new ArrayList<String>());
+ this(paths,lines,new ArrayList<>());
}
public SetAclPaths(List<String> paths,List<AclLine> lines, List<String>
aclOptions){
@@ -46,7 +47,14 @@ public class SetAclPaths extends AclGroupBase {
sb.append(super.getParametersDescription());
return sb.toString();
}
-
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ String topline = String.format("set ACL on %s%s%n",
pathsToString(paths), getAclOptionsString());
+ return asRepoInit(topline, false);
+ }
+
public List<String> getPaths() {
return paths;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
index 8c8b3b5..c8d8538 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipalBased.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
/** Set ACL statement that groups a set of AclLines
@@ -46,7 +47,14 @@ public class SetAclPrincipalBased extends AclGroupBase {
sb.append(super.getParametersDescription());
return sb.toString();
}
-
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ String topline = String.format("set principal ACL for %s%s%n",
listToString(principals), getAclOptionsString());
+ return asRepoInit(topline, true);
+ }
+
public List<String> getPrincipals() {
return principals;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
index d740cc4..2c8c1b1 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetAclPrincipals.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
import org.osgi.annotation.versioning.ProviderType;
/** Set ACL statement that groups a set of AclLines
@@ -46,7 +47,22 @@ public class SetAclPrincipals extends AclGroupBase {
sb.append(super.getParametersDescription());
return sb.toString();
}
-
+
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ if (getLines().stream().anyMatch(line -> {
+ List<String> paths = line.getProperty(AclLine.PROP_PATHS);
+ return paths == null || paths.isEmpty();
+ })) {
+ String topline = String.format("set repository ACL for %s%s%n",
listToString(principals), getAclOptionsString());
+ return asRepoInit(topline, true);
+ } else {
+ String topline = String.format("set ACL for %s%s%n",
listToString(principals), getAclOptionsString());
+ return asRepoInit(topline, true);
+ }
+ }
+
public List<String> getPrincipals() {
return principals;
}
diff --git
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetProperties.java
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetProperties.java
index f72ca11..48a70ad 100644
---
a/src/main/java/org/apache/sling/repoinit/parser/operations/SetProperties.java
+++
b/src/main/java/org/apache/sling/repoinit/parser/operations/SetProperties.java
@@ -18,8 +18,15 @@
package org.apache.sling.repoinit.parser.operations;
+import java.util.Calendar;
+import java.util.Formatter;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.apache.jackrabbit.util.ISO8601;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.osgi.annotation.versioning.ProviderType;
@ProviderType
@@ -46,6 +53,43 @@ public class SetProperties extends Operation {
return sb.toString();
}
+ @NotNull
+ @Override
+ public String asRepoInitString() {
+ // FIXME: see SLING-10238 for type and quoted values that cannot be
generated
+ // exactly as they were originally defined in repo-init
+ try (Formatter formatter = new Formatter()) {
+ formatter.format("set properties on %s%n", pathsToString(paths));
+ for (PropertyLine line : lines) {
+ String type = (line.getPropertyType() == null) ? "" : "{" +
line.getPropertyType().name() + "}";
+ String values = valuesToString(line.getPropertyValues(),
line.getPropertyType());
+ if (line.isDefault()) {
+ formatter.format("default %s%s to %s%n",
line.getPropertyName(), type, values);
+ } else {
+ formatter.format("set %s%s to %s%n",
line.getPropertyName(), type, values);
+ }
+ }
+ formatter.format("end%n");
+ return formatter.toString();
+ }
+ }
+
+ @NotNull
+ private static String valuesToString(@NotNull List<Object> values,
@Nullable PropertyLine.PropertyType type) {
+ List<String> strings = values.stream()
+ .map(o -> {
+ if (type == null || type ==
PropertyLine.PropertyType.String) {
+ return escapeQuotes(Objects.toString(o, ""));
+ } else if (type == PropertyLine.PropertyType.Date) {
+ return "\"" + ISO8601.format((Calendar) o) + "\"";
+ } else {
+ return Objects.toString(o, null);
+ }
+ })
+ .collect(Collectors.toList());
+ return listToString(strings);
+ }
+
public List<String> getPaths() {
return paths;
}
diff --git
a/src/test/java/org/apache/sling/repoinit/parser/operations/AsRepoInitTest.java
b/src/test/java/org/apache/sling/repoinit/parser/operations/AsRepoInitTest.java
new file mode 100644
index 0000000..01c2d52
--- /dev/null
+++
b/src/test/java/org/apache/sling/repoinit/parser/operations/AsRepoInitTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.apache.sling.repoinit.parser.impl.RepoInitParserService;
+import org.apache.sling.repoinit.parser.test.ParserTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** Similar to {@link ParserTest} but uses {@link
Operation#asRepoInitString()})
+ * to rebuild the input script after parsing it, to verify that that operation
+ * returns equivalent statements.
+ */
+@RunWith(Parameterized.class)
+public class AsRepoInitTest {
+
+ private final ParserTest.TestCase tc;
+
+ @Parameters(name="{0}")
+ public static Collection<Object[]> data() throws IOException {
+ return ParserTest.TestCase.buildTestData();
+ }
+
+ public AsRepoInitTest(ParserTest.TestCase tc) {
+ this.tc = tc;
+ }
+
+ /** Rebuild the input script using {@link Operation#asRepoInitString()}) */
+ private static Reader rebuildInputScript(Reader input) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ for (Operation o : new RepoInitParserService().parse(input)) {
+ sb.append(o.asRepoInitString());
+ }
+ return new StringReader(sb.toString());
+ }
+
+ @Test
+ public void checkResultAsRepoInit() throws Exception {
+ try {
+ ParserTest.TestCase.validate(rebuildInputScript(tc.input),
tc.expected);
+ } finally {
+ tc.close();
+ }
+ }
+}
diff --git
a/src/test/java/org/apache/sling/repoinit/parser/test/ParserTest.java
b/src/test/java/org/apache/sling/repoinit/parser/test/ParserTest.java
index d51dd6d..3195c58 100644
--- a/src/test/java/org/apache/sling/repoinit/parser/test/ParserTest.java
+++ b/src/test/java/org/apache/sling/repoinit/parser/test/ParserTest.java
@@ -49,10 +49,10 @@ public class ParserTest {
public static final String DEFAULT_ENCODING = "UTF-8";
- static class TestCase {
- final Reader input;
+ public static class TestCase {
+ public final Reader input;
final String inputFilename;
- final InputStream expected;
+ public final InputStream expected;
final String outputFilename;
private static final String PREFIX = "/testcases/test-";
@@ -74,7 +74,7 @@ public class ParserTest {
expected = getClass().getResourceAsStream(outputFilename);
}
- static TestCase build(int index) throws IOException {
+ public static TestCase build(int index) throws IOException {
final TestCase result = new TestCase(index);
if(result.input == null || result.expected == null) {
return null;
@@ -82,7 +82,7 @@ public class ParserTest {
return result;
}
- void close() {
+ public void close() {
try {
input.close();
} catch(IOException ignored) {
@@ -92,21 +92,41 @@ public class ParserTest {
} catch(IOException ignored) {
}
}
+
+ public static void validate(Reader validateInput, InputStream
validateExpected) throws RepoInitParsingException, IOException {
+ final String expected = IOUtils.toString(validateExpected,
DEFAULT_ENCODING).trim();
+ final StringWriter sw = new StringWriter();
+ final OperationVisitor v = new OperationToStringVisitor(new
PrintWriter(sw));
+ final List<Operation> result = new
RepoInitParserService().parse(validateInput);
+ for(Operation o : result) {
+ o.accept(v);
+ }
+ sw.flush();
+ String actual = sw.toString().trim();
+
+ // normalize line endings to ensure tests run on windows as well
+ actual = actual.replaceAll("\r\n", "\n");
+
+ assertEquals(expected, actual);
+ }
+
+ public static Collection<Object[]> buildTestData() throws IOException {
+ final List<Object []> result = new ArrayList<>();
+ for(int i=0; i < 100; i++) {
+ final ParserTest.TestCase tc = ParserTest.TestCase.build(i);
+ if(tc != null) {
+ result.add(new Object[] { tc });
+ }
+ }
+ return result;
+ }
}
private final TestCase tc;
@Parameters(name="{0}")
public static Collection<Object[]> data() throws IOException {
- final List<Object []> result = new ArrayList<>();
- for(int i=0; i < 100; i++) {
- final TestCase tc = TestCase.build(i);
- if(tc != null) {
- result.add(new Object[] { tc });
- }
- }
- return result;
-
+ return TestCase.buildTestData();
}
public ParserTest(TestCase tc) {
@@ -115,21 +135,8 @@ public class ParserTest {
@Test
public void checkResult() throws RepoInitParsingException, IOException {
- final String expected = IOUtils.toString(tc.expected,
DEFAULT_ENCODING).trim();
try {
- final StringWriter sw = new StringWriter();
- final OperationVisitor v = new OperationToStringVisitor(new
PrintWriter(sw));
- final List<Operation> result = new
RepoInitParserService().parse(tc.input);
- for(Operation o : result) {
- o.accept(v);
- }
- sw.flush();
- String actual = sw.toString().trim();
-
- // normalize line endings to ensure tests run on windows as well
- actual = actual.replaceAll("\r\n", "\n");
-
- assertEquals(expected, actual);
+ TestCase.validate(tc.input, tc.expected);
} finally {
tc.close();
}