SLING-10468 : Converted content package is missing some .content.xml (replace hardcoded sys-user-relpath)
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
index b528448..e0c91ef 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/DefaultAclManager.java
@@ -26,6 +26,7 @@
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.cpconverter.repoinit.NoOpVisitor;
 import org.apache.sling.feature.cpconverter.repoinit.OperationProcessor;
+import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.apache.sling.repoinit.parser.RepoInitParsingException;
@@ -96,7 +97,7 @@
     private RepoPath userRootPath;
 
     public DefaultAclManager() {
-        this(null, "system");
+        this(null, ConverterConstants.SYSTEM_USER_REL_PATH_DEFAULT);
     }
     public DefaultAclManager(@Nullable String enforcePrincipalBasedSupportedPath, @NotNull String systemRelPath) {
         if (enforcePrincipalBasedSupportedPath != null && !enforcePrincipalBasedSupportedPath.contains(systemRelPath)) {
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
index 59b72fa..3cff3fc 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
@@ -37,6 +37,7 @@
 import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.filtering.RegexBasedResourceFilter;
 import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager;
+import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.jetbrains.annotations.NotNull;
@@ -111,7 +112,7 @@
     private String enforcePrincipalBasedSupportedPath = null;
 
     @Option(names= {"--system-user-rel-path"}, description = "Relative path for system user as configured with Apache Jackrabbit Oak", required = false)
-    private String systemUserRelPath = "system";
+    private String systemUserRelPath = ConverterConstants.SYSTEM_USER_REL_PATH_DEFAULT;
 
     @Option(names = { "--enforce-servicemapping-by-principal" }, description = "Converts service user mappings with the form 'service:sub=userID' to 'service:sub=[principalname]'. Note, this may result in group membership no longer being resolved upon service login.", required = false)
     private boolean enforceServiceMappingByPrincipal = false;
@@ -208,7 +209,7 @@
                 try (ContentPackage2FeatureModelConverter converter = new ContentPackage2FeatureModelConverter(strictValidation)) {
                     converter.setFeaturesManager(featuresManager)
                              .setBundlesDeployer(new LocalMavenRepositoryArtifactsDeployer(artifactsOutputDirectory))
-                             .setEntryHandlersManager(new DefaultEntryHandlersManager(entryHandlerConfigsMap, !disableInstallerPolicy, slingInitialContentPolicy))
+                             .setEntryHandlersManager(new DefaultEntryHandlersManager(entryHandlerConfigsMap, !disableInstallerPolicy, slingInitialContentPolicy, systemUserRelPath))
                              .setAclManager(aclManager)
                              .setEmitter(DefaultPackagesEventsEmitter.open(featureModelsOutputDirectory))
                              .setFailOnMixedPackages(failOnMixedPackages)
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
index 978facd..a162bdb 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractUserEntryHandler.java
@@ -21,6 +21,7 @@
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
 import org.jetbrains.annotations.NotNull;
@@ -32,8 +33,7 @@
 
 abstract class AbstractUserEntryHandler extends AbstractRegexEntryHandler {
     
-    // FIXME: use first segment of 'systemUserRelPath' config value instead of hardcoding 
-    private static final String SYSTEM_USER_SEGMENT = "/system/";
+    private String systemUserSegment = createSegment(ConverterConstants.SYSTEM_USER_REL_PATH_DEFAULT);
 
     AbstractUserEntryHandler(@NotNull String rexex) {
         super(rexex);
@@ -50,7 +50,7 @@
             byte[] tmp = IOUtils.toByteArray((archive.openInputStream(entry)));
             AbstractUserParser parser = createParser(converter, originalPath, intermediatePath);
             boolean converted = parser.parse(new ByteArrayInputStream(tmp));
-            if (!converted && !path.contains(SYSTEM_USER_SEGMENT)) {
+            if (!converted && !path.contains(systemUserSegment)) {
                 // write back regular users, groups and their intermediate folders that did not get converted into
                 // repo-init statements to the content package
                 VaultPackageAssembler assembler = converter.getMainPackageAssembler();
@@ -67,4 +67,12 @@
 
     abstract AbstractUserParser createParser(@NotNull ContentPackage2FeatureModelConverter converter, @NotNull RepoPath originalPath, @NotNull RepoPath intermediatePath);
 
+    void setSystemUserRelPath(@NotNull String systemUserRelPath) {
+        int index = systemUserRelPath.indexOf('/');
+        systemUserSegment = (index == -1) ? createSegment(systemUserRelPath) : createSegment(systemUserRelPath.substring(0, index));
+    }
+    
+    private static String createSegment(@NotNull String relPath) {
+        return "/" + relPath + "/";
+    }
 }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/DefaultEntryHandlersManager.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/DefaultEntryHandlersManager.java
index f6f615a..f80a88e 100644
--- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/DefaultEntryHandlersManager.java
+++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/DefaultEntryHandlersManager.java
@@ -17,6 +17,7 @@
 package org.apache.sling.feature.cpconverter.handlers;
 
 import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter.SlingInitialContentPolicy;
+import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -31,10 +32,11 @@
     private final List<EntryHandler> entryHandlers = new LinkedList<>();
 
     public DefaultEntryHandlersManager() {
-        this(Collections.emptyMap(), false, SlingInitialContentPolicy.KEEP);
+        this(Collections.emptyMap(), false, SlingInitialContentPolicy.KEEP, ConverterConstants.SYSTEM_USER_REL_PATH_DEFAULT);
     }
 
-    public DefaultEntryHandlersManager(@NotNull Map<String, String> configs, boolean enforceConfigurationsAndBundlesBelowProperFolder, SlingInitialContentPolicy slingInitialContentPolicy) {
+    public DefaultEntryHandlersManager(@NotNull Map<String, String> configs, boolean enforceConfigurationsAndBundlesBelowProperFolder, 
+                                       SlingInitialContentPolicy slingInitialContentPolicy, @NotNull String systemUserRelPath) {
         ServiceLoader<EntryHandler> entryHandlersLoader = ServiceLoader.load(EntryHandler.class);
         for (EntryHandler entryHandler : entryHandlersLoader) {
             if (configs.containsKey(entryHandler.getClass().getName())) {
@@ -45,6 +47,8 @@
             } else if (entryHandler instanceof BundleEntryHandler) {
                 ((BundleEntryHandler) entryHandler).setEnforceBundlesBelowInstallFolder(enforceConfigurationsAndBundlesBelowProperFolder);
                 ((BundleEntryHandler) entryHandler).setSlingInitialContentPolicy(slingInitialContentPolicy);
+            } else if (entryHandler instanceof AbstractUserEntryHandler) {
+                ((AbstractUserEntryHandler) entryHandler).setSystemUserRelPath(systemUserRelPath);
             }
             addEntryHandler(entryHandler);
         }
diff --git a/src/main/java/org/apache/sling/feature/cpconverter/shared/ConverterConstants.java b/src/main/java/org/apache/sling/feature/cpconverter/shared/ConverterConstants.java
new file mode 100644
index 0000000..a76f96a
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/cpconverter/shared/ConverterConstants.java
@@ -0,0 +1,25 @@
+/*
+ * 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.feature.cpconverter.shared;
+
+public final class ConverterConstants {
+    
+    private ConverterConstants() {}
+    
+    public static final String SYSTEM_USER_REL_PATH_DEFAULT = "system";
+    
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
index 32a39b6..ed67aaa 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java
@@ -69,13 +69,17 @@
 import org.apache.sling.feature.cpconverter.filtering.RegexBasedResourceFilter;
 import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager;
 import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager;
+import org.apache.sling.feature.cpconverter.shared.ConverterConstants;
 import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter;
 import org.apache.sling.feature.io.json.FeatureJSONReader;
 import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class ContentPackage2FeatureModelConverterTest {
 
     /**
@@ -94,10 +98,23 @@
 
     private ContentPackage2FeatureModelConverter converter;
     private EntryHandlersManager handlersManager;
-
+    
+    private final String systemUserRelPath;
+    
+    @Parameterized.Parameters(name = "name={1}")
+    public static Collection<Object[]> parameters() {
+        return Arrays.asList(
+                new Object[] {ConverterConstants.SYSTEM_USER_REL_PATH_DEFAULT, "Default system user rel-path"},
+                new Object[] { "system/cq:services", "Modified system user rel-path"});
+    }
+    
+    public ContentPackage2FeatureModelConverterTest(@NotNull String systemUserRelPath, @NotNull String name) {
+        this.systemUserRelPath = systemUserRelPath;
+    }
+        
     @Before
     public void setUp() {
-        handlersManager = new DefaultEntryHandlersManager();
+        handlersManager = new DefaultEntryHandlersManager(Collections.emptyMap(), false, ContentPackage2FeatureModelConverter.SlingInitialContentPolicy.KEEP, systemUserRelPath);
         converter = new ContentPackage2FeatureModelConverter()
                     .setEntryHandlersManager(handlersManager)
                     .setAclManager(new DefaultAclManager());