You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by js...@apache.org on 2024/05/28 08:35:21 UTC

(sling-org-apache-sling-jcr-repoinit) 01/01: SLING-12329 - Backwards compatibility for legacy repoinit statement reordering

This is an automated email from the ASF dual-hosted git repository.

jsedding pushed a commit to branch fix/SLING-12329-legacy-reordering-fallback
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-repoinit.git

commit fd45ec36b8de98334c69661cfd9e50955999060f
Author: Julian Sedding <js...@apache.org>
AuthorDate: Tue May 28 10:35:08 2024 +0200

    SLING-12329 - Backwards compatibility for legacy repoinit statement reordering
---
 .../repoinit/impl/JcrRepoInitOpsProcessorImpl.java | 72 ++++++++++++++++++----
 .../sling/jcr/repoinit/ExecutionOrderTest.java     | 45 +++++++++++---
 .../org/apache/sling/jcr/repoinit/LogCapture.java  |  6 +-
 3 files changed, 100 insertions(+), 23 deletions(-)

diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/JcrRepoInitOpsProcessorImpl.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/JcrRepoInitOpsProcessorImpl.java
index f0c6981..b072975 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/JcrRepoInitOpsProcessorImpl.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/JcrRepoInitOpsProcessorImpl.java
@@ -17,14 +17,20 @@
 package org.apache.sling.jcr.repoinit.impl;
 
 import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Stream;
 
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
 import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
 import org.apache.sling.repoinit.parser.operations.Operation;
+import org.apache.sling.repoinit.parser.operations.OperationVisitor;
 import org.osgi.framework.Constants;
 import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.singleton;
@@ -38,28 +44,70 @@ import static java.util.Collections.singleton;
         })
 public class JcrRepoInitOpsProcessorImpl implements JcrRepoInitOpsProcessor {
 
+    private static final Logger log = LoggerFactory.getLogger(JcrRepoInitOpsProcessorImpl.class);
+
     /**
      * Apply the supplied operations: first the namespaces and nodetypes
      * registrations, then the service users, paths and ACLs.
      */
     @Override
     public void apply(Session session, List<Operation> ops) {
-        Stream.of(
-                // register namespaces first
-                singleton(new NamespacesVisitor(session)),
-                // then create node types and privileges, both use namespaces
-                asList(
+        AtomicReference<Operation> lastAttemptedOperation = new AtomicReference<>();
+        try {
+            Stream.of(
+                    // register namespaces first
+                    singleton(new NamespacesVisitor(session)),
+                    // then create node types and privileges, both use namespaces
+                    asList(
+                            new NodetypesVisitor(session),
+                            new PrivilegeVisitor(session)),
+                    // finally apply everything else
+                    asList(
+                            new UserVisitor(session),
+                            new NodeVisitor(session),
+                            new AclVisitor(session),
+                            new GroupMembershipVisitor(session),
+                            new NodePropertiesVisitor(session))
+            ).forEach(visitorGroup -> {
+                ops.forEach(op -> {
+                    lastAttemptedOperation.set(op);
+                    visitorGroup.forEach(op::accept);
+                });
+            });
+        } catch (RepoInitException originalFailure) {
+            // support legacy statement reordering for backwards compatibility
+            try {
+                session.refresh(false); // drop transient changes
+
+                final OperationVisitor[] visitors = {
+                        new NamespacesVisitor(session),
                         new NodetypesVisitor(session),
-                        new PrivilegeVisitor(session)),
-                // finally apply everything else
-                asList(
+                        new PrivilegeVisitor(session),
                         new UserVisitor(session),
                         new NodeVisitor(session),
                         new AclVisitor(session),
                         new GroupMembershipVisitor(session),
-                        new NodePropertiesVisitor(session))
-        ).forEach(visitorGroup -> {
-            ops.forEach(op -> visitorGroup.forEach(op::accept));
-        });
+                        new NodePropertiesVisitor(session)
+                };
+
+                for (OperationVisitor v : visitors) {
+                    for (Operation op : ops) {
+                        op.accept(v);
+                    }
+                }
+
+                log.warn("DEPRECATION - The repoinit script being executed relies on a bug causing repoinit " +
+                        "statements to be reordered. Please review and fix the ordering of your repoinit statements. " +
+                        "The code supporting the legacy order will be removed in a future release. The new code " +
+                        "failed on the statement \"{}\"",
+                        Optional.ofNullable(lastAttemptedOperation.get()).map(Operation::asRepoInitString).orElse("unknown"));
+            } catch (Exception legacyFailure) {
+                // rethrow the originalFailure if the legacy code also failed
+                throw originalFailure;
+            }
+        }
+
+
+
     }
 }
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/ExecutionOrderTest.java b/src/test/java/org/apache/sling/jcr/repoinit/ExecutionOrderTest.java
index b27295f..c0f4646 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/ExecutionOrderTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/ExecutionOrderTest.java
@@ -16,25 +16,21 @@
  */
 package org.apache.sling.jcr.repoinit;
 
-import org.apache.jackrabbit.api.security.user.Group;
-import org.apache.jackrabbit.api.security.user.UserManager;
+import ch.qos.logback.classic.Level;
 import org.apache.sling.jcr.repoinit.impl.TestUtil;
-import org.apache.sling.jcr.repoinit.impl.UserUtil;
 import org.apache.sling.repoinit.parser.RepoInitParsingException;
-import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
-import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
-import javax.jcr.Value;
 import java.util.UUID;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 /** Verify that namespaces and nodetypes are executed before path creation. But otherwise,
  * the execution order should match the order of the statements.
@@ -43,9 +39,9 @@ public class ExecutionOrderTest {
 
     @Rule
     public final SlingContext context = new SlingContext(ResourceResolverType.JCR_OAK);
-    
+
     private TestUtil U;
-    
+
     private static final String TEST_ID = UUID.randomUUID().toString();
     private static final String NS_PREFIX = ExecutionOrderTest.class.getSimpleName();
     private static final String NS_URI = "uri:" + NS_PREFIX + ":" + TEST_ID;
@@ -89,4 +85,37 @@ public class ExecutionOrderTest {
         U.assertPrivileges(GROUP_NAME, PATH, true, "jcr:read");
         U.assertPrivileges(GROUP_NAME, PATH, false, "jcr:write");
     }
+
+    @Test
+    public void legacySetAclBeforeCreatingGroupTest() throws Exception {
+        try (LogCapture capture = new LogCapture("org.apache.sling.jcr.repoinit.impl.JcrRepoInitOpsProcessorImpl", true)) {
+            U.parseAndExecute(
+                    "create path (nt:folder) " + PATH,
+                    "set ACL for " + GROUP_NAME,
+                    "  allow jcr:read on " + PATH,
+                    "  deny jcr:write on " + PATH,
+                    "end",
+                    "create group " + GROUP_NAME
+            );
+
+            capture.assertContains(Level.WARN, "DEPRECATION", "set ACL for " + GROUP_NAME);
+        } catch (RuntimeException e) {
+            fail("Legacy support should have reordered \"create group\" before \"set ACL\"");
+        }
+    }
+
+    @Test
+    public void legacyAddMemberBeforeCreatingGroupTest() throws Exception {
+        try (LogCapture capture = new LogCapture("org.apache.sling.jcr.repoinit.impl.JcrRepoInitOpsProcessorImpl", true)) {
+            U.parseAndExecute(
+                    "create group " + GROUP_NAME + "_1",
+                    "add " + GROUP_NAME + "_1 to group " + GROUP_NAME,
+                    "create group " + GROUP_NAME // reordered by legacy code
+            );
+
+            capture.assertContains(Level.WARN, "DEPRECATION", "add " + GROUP_NAME + "_1 to group ");
+        } catch (RuntimeException e) {
+            fail("Legacy support should have reordered \"create group\" before \"add ... to group\"");
+        }
+    }
 }
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/LogCapture.java b/src/test/java/org/apache/sling/jcr/repoinit/LogCapture.java
index 8a4a5e4..153664f 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/LogCapture.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/LogCapture.java
@@ -31,9 +31,9 @@ import ch.qos.logback.classic.LoggerContext;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.read.ListAppender;
 
-/** 
- * Capture logs for testing 
- * 
+/**
+ * Capture logs for testing
+ *
  * Initially cloned from: https://github.com/apache/sling-org-apache-sling-graphql-core/blob/0b1c1dd72ed04324ea84d2227c3223ec65b0b21e/src/test/java/org/apache/sling/graphql/core/util/LogCapture.java
  */
 class LogCapture extends ListAppender<ILoggingEvent> implements AutoCloseable {