diff --git a/changes.xml b/changes.xml
index 6979831..35d921d 100644
--- a/changes.xml
+++ b/changes.xml
@@ -24,6 +24,9 @@
+
+ Add JsonOsgiConfigPostProcessor to support reading a combined set of OSGi configuration for run modes from .osgiconfig.json files.
+
ProvisioningOsgiConfigPostProcessor: Write OSGi configurations as .cfg.json files instead of .config files.
diff --git a/conga-sling-plugin/pom.xml b/conga-sling-plugin/pom.xml
index 3a9cab8..9b7917d 100644
--- a/conga-sling-plugin/pom.xml
+++ b/conga-sling-plugin/pom.xml
@@ -79,6 +79,13 @@
compile
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.16.1
+ compile
+
+
org.apache.felix
org.apache.felix.cm.json
diff --git a/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/JsonOsgiConfigPostProcessor.java b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/JsonOsgiConfigPostProcessor.java
new file mode 100644
index 0000000..46c5aaa
--- /dev/null
+++ b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/JsonOsgiConfigPostProcessor.java
@@ -0,0 +1,85 @@
+/*
+ * #%L
+ * wcm.io
+ * %%
+ * Copyright (C) 2024 wcm.io
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package io.wcm.devops.conga.plugins.sling.postprocessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.provisioning.model.Model;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import io.wcm.devops.conga.generator.GeneratorException;
+import io.wcm.devops.conga.generator.spi.PostProcessorPlugin;
+import io.wcm.devops.conga.generator.spi.context.FileContext;
+import io.wcm.devops.conga.generator.spi.context.PostProcessorContext;
+import io.wcm.devops.conga.plugins.sling.util.JsonOsgiConfigUtil;
+import io.wcm.devops.conga.plugins.sling.util.ProvisioningUtil;
+
+/**
+ * Transforms a combined JSON file containing OSGi configurations into individual OSGi configuration files.
+ */
+public class JsonOsgiConfigPostProcessor implements PostProcessorPlugin {
+
+ /**
+ * Plugin name
+ */
+ public static final String NAME = "sling-json-osgiconfig";
+
+ /**
+ * File extension
+ */
+ public static final String FILE_EXTENSION = ".osgiconfig.json";
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public boolean accepts(FileContext file, PostProcessorContext context) {
+ return StringUtils.endsWith(file.getFile().getName(), FILE_EXTENSION);
+ }
+
+ @Override
+ @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
+ public List apply(FileContext fileContext, PostProcessorContext context) {
+ File file = fileContext.getFile();
+ try {
+ // read JSON file with combined configurations
+ Model model = JsonOsgiConfigUtil.readToProvisioningModel(file);
+
+ // generate OSGi configurations
+ List files = ProvisioningUtil.generateOsgiConfigurations(model, file.getParentFile(), context);
+
+ // delete provisioning file after transformation
+ Files.delete(file.toPath());
+
+ // return list of generated osgi configuration files
+ return files;
+ }
+ catch (IOException ex) {
+ throw new GeneratorException("Unable to parse JSON file with OSGi configurations.", ex);
+ }
+ }
+
+}
diff --git a/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/ProvisioningOsgiConfigPostProcessor.java b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/ProvisioningOsgiConfigPostProcessor.java
index 9a759e7..9f855bf 100644
--- a/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/ProvisioningOsgiConfigPostProcessor.java
+++ b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/postprocessor/ProvisioningOsgiConfigPostProcessor.java
@@ -20,10 +20,8 @@
package io.wcm.devops.conga.plugins.sling.postprocessor;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Dictionary;
+import java.nio.file.Files;
import java.util.List;
import org.apache.sling.provisioning.model.Model;
@@ -33,12 +31,11 @@
import io.wcm.devops.conga.generator.spi.PostProcessorPlugin;
import io.wcm.devops.conga.generator.spi.context.FileContext;
import io.wcm.devops.conga.generator.spi.context.PostProcessorContext;
-import io.wcm.devops.conga.plugins.sling.util.ConfigConsumer;
-import io.wcm.devops.conga.plugins.sling.util.OsgiConfigUtil;
import io.wcm.devops.conga.plugins.sling.util.ProvisioningUtil;
/**
- * Transforms a Sling Provisioning file into OSGi configurations (ignoring all other provisioning contents).
+ * Transforms a Sling Provisioning file into OSGi configuration files (.cfg.json).
+ * Repoinit statements are supported as well, all other provisioning contents are ignored
*/
public class ProvisioningOsgiConfigPostProcessor implements PostProcessorPlugin {
@@ -64,41 +61,17 @@ public List apply(FileContext fileContext, PostProcessorContext con
try {
// generate OSGi configurations
Model model = ProvisioningUtil.getModel(fileContext);
- List files = generateOsgiConfigurations(model, file.getParentFile(), context);
+ List files = ProvisioningUtil.generateOsgiConfigurations(model, file.getParentFile(), context);
// delete provisioning file after transformation
- file.delete();
+ Files.delete(file.toPath());
// return list of generated osgi configuration files
return files;
}
catch (IOException ex) {
- throw new GeneratorException("Unable to post-process sling provisioning OSGi configurations.", ex);
+ throw new GeneratorException("Unable to post-process Sling Provisioning OSGi configurations.", ex);
}
}
- /**
- * Generate OSGi configuration for all feature and run modes.
- * @param model Provisioning Model
- * @param dir Target directory
- * @param context Post processor context
- */
- private List generateOsgiConfigurations(Model model, File dir, PostProcessorContext context) throws IOException {
- return ProvisioningUtil.visitOsgiConfigurations(model, new ConfigConsumer() {
- @Override
- @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
- public FileContext accept(String path, Dictionary properties) throws IOException {
- context.getLogger().info(" Generate {}", path);
-
- File confFile = new File(dir, path);
- confFile.getParentFile().mkdirs();
- try (FileOutputStream os = new FileOutputStream(confFile)) {
- OsgiConfigUtil.write(os, properties);
- }
-
- return new FileContext().file(confFile).charset(StandardCharsets.UTF_8);
- }
- });
- }
-
}
diff --git a/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/util/JsonOsgiConfigUtil.java b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/util/JsonOsgiConfigUtil.java
new file mode 100644
index 0000000..b358e4e
--- /dev/null
+++ b/conga-sling-plugin/src/main/java/io/wcm/devops/conga/plugins/sling/util/JsonOsgiConfigUtil.java
@@ -0,0 +1,158 @@
+/*
+ * #%L
+ * wcm.io
+ * %%
+ * Copyright (C) 2024 wcm.io
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package io.wcm.devops.conga.plugins.sling.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.RunMode;
+import org.apache.sling.provisioning.model.Section;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.wcm.devops.conga.plugins.sling.postprocessor.JsonOsgiConfigPostProcessor;
+
+/**
+ * Helper class for reading JSON files.
+ */
+public final class JsonOsgiConfigUtil {
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private static final TypeReference