Skip to content

Commit b114a70

Browse files
AEM Page persistence strategy: Add OSGi configuration property "Config Name Deny List" (#11)
which allows to configure a list of configuration names that should not be persisted as AEM pages By default, this contains the configuration name com.adobe.aem.wcm.site.manager.config.SiteConfig, which is accessed internally by AEM using JCR queries and assuming a simplified persistence structure.
1 parent 1640b5e commit b114a70

File tree

3 files changed

+113
-24
lines changed

3 files changed

+113
-24
lines changed

changes.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
xsi:schemaLocation="http://maven.apache.org/changes/2.0.0 https://maven.apache.org/xsd/changes-2.0.0.xsd">
2525
<body>
2626

27+
<release version="1.10.4" date="not released">
28+
<action type="update" dev="sseifert" issue="11">
29+
AEM Page persistence strategy: Add OSGi configuration property "Config Name Deny List" which allows to configure a list of configuration names that should not be persisted as AEM pages.
30+
By default, this contains the configuration name com.adobe.aem.wcm.site.manager.config.SiteConfig, which is accessed internally by AEM using JCR queries and assuming a simplified persistence structure.
31+
</action>
32+
</release>
33+
2734
<release version="1.10.2" date="2025-01-13">
2835
<action type="fix" dev="sseifert" issue="9">
2936
AEM Page persistence strategy: Saving of Context-Aware configuration collections - restore previous behavior of setting last modified date of all items regardless of actual data changes or not.

src/main/java/io/wcm/caconfig/extensions/persistence/impl/PagePersistenceStrategy.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@
3232
import static io.wcm.caconfig.extensions.persistence.impl.PersistenceUtils.replaceProperties;
3333
import static io.wcm.caconfig.extensions.persistence.impl.PersistenceUtils.updatePageLastMod;
3434

35+
import java.util.Arrays;
36+
import java.util.Set;
37+
3538
import org.apache.sling.api.resource.Resource;
3639
import org.apache.sling.api.resource.ResourceResolver;
40+
import org.apache.sling.api.resource.ResourceUtil;
3741
import org.apache.sling.api.resource.ValueMap;
3842
import org.apache.sling.caconfig.management.ConfigurationManagementSettings;
3943
import org.apache.sling.caconfig.spi.ConfigurationCollectionPersistData;
@@ -87,6 +91,13 @@ public class PagePersistenceStrategy implements ConfigurationPersistenceStrategy
8791
description = "Priority of persistence strategy (higher = higher priority).")
8892
int service_ranking() default 1500;
8993

94+
@AttributeDefinition(name = "Config Name Deny List",
95+
description = "List of context-aware configuration names this persistence implementation should ignore.")
96+
String[] configNameDenyList() default {
97+
// ignore because AEM uses JCR query to fetch config values, assuming a different persistence structure
98+
"com.adobe.aem.wcm.site.manager.config.SiteConfig"
99+
};
100+
90101
}
91102

92103
private static final String DEFAULT_CONFIG_NODE_TYPE = NT_UNSTRUCTURED;
@@ -99,12 +110,14 @@ public class PagePersistenceStrategy implements ConfigurationPersistenceStrategy
99110
private boolean enabled;
100111
private String resourceType;
101112
private boolean collectionMarkAllItemsUpdated;
113+
private Set<String> configNameDenyList;
102114

103115
@Activate
104116
void activate(Config config) {
105117
this.enabled = config.enabled();
106118
this.resourceType = config.resourceType();
107119
this.collectionMarkAllItemsUpdated = config.collectionMarkAllItemsUpdated();
120+
this.configNameDenyList = Set.copyOf(Arrays.asList(config.configNameDenyList()));
108121
}
109122

110123
@Override
@@ -157,7 +170,7 @@ public String getCollectionItemResourcePath(@NotNull String resourcePath) {
157170

158171
@Override
159172
public String getConfigName(@NotNull String configName, @Nullable String relatedConfigPath) {
160-
if (!enabled) {
173+
if (!enabled && isConfigNameDenied(configName)) {
161174
return null;
162175
}
163176
if (containsJcrContent(configName)) {
@@ -168,7 +181,7 @@ public String getConfigName(@NotNull String configName, @Nullable String related
168181

169182
@Override
170183
public String getCollectionParentConfigName(@NotNull String configName, @Nullable String relatedConfigPath) {
171-
if (!enabled) {
184+
if (!enabled && isConfigNameDenied(configName)) {
172185
return null;
173186
}
174187
return configName;
@@ -182,7 +195,7 @@ public String getCollectionItemConfigName(@NotNull String configName, @Nullable
182195
@Override
183196
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
184197
public boolean persistConfiguration(@NotNull ResourceResolver resolver, @NotNull String configResourcePath, @NotNull ConfigurationPersistData data) {
185-
if (!enabled) {
198+
if (!enabled || isConfigResourcePathDenied(configResourcePath)) {
186199
return false;
187200
}
188201
String path = getResourcePath(configResourcePath);
@@ -200,7 +213,7 @@ public boolean persistConfiguration(@NotNull ResourceResolver resolver, @NotNull
200213
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
201214
public boolean persistConfigurationCollection(@NotNull ResourceResolver resolver, @NotNull String configResourceCollectionParentPath,
202215
@NotNull ConfigurationCollectionPersistData data) {
203-
if (!enabled) {
216+
if (!enabled || isConfigResourcePathDenied(configResourceCollectionParentPath)) {
204217
return false;
205218
}
206219

@@ -242,7 +255,7 @@ public boolean persistConfigurationCollection(@NotNull ResourceResolver resolver
242255

243256
@Override
244257
public boolean deleteConfiguration(@NotNull ResourceResolver resolver, @NotNull String configResourcePath) {
245-
if (!enabled) {
258+
if (!enabled || isConfigResourcePathDenied(configResourcePath)) {
246259
return false;
247260
}
248261
Resource configResource = resolver.getResource(configResourcePath);
@@ -255,4 +268,13 @@ public boolean deleteConfiguration(@NotNull ResourceResolver resolver, @NotNull
255268
return true;
256269
}
257270

271+
private boolean isConfigNameDenied(@NotNull String configName) {
272+
return configNameDenyList.contains(configName);
273+
}
274+
275+
private boolean isConfigResourcePathDenied(@NotNull String configResourcePath) {
276+
String resourceName = ResourceUtil.getName(configResourcePath);
277+
return isConfigNameDenied(resourceName);
278+
}
279+
258280
}

src/test/java/io/wcm/caconfig/extensions/persistence/impl/PagePersistenceStrategyTest.java

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.Calendar;
3535
import java.util.List;
3636

37+
import org.apache.sling.api.resource.Resource;
3738
import org.apache.sling.caconfig.ConfigurationBuilder;
3839
import org.apache.sling.caconfig.management.ConfigurationManager;
3940
import org.apache.sling.hamcrest.ResourceMatchers;
@@ -113,25 +114,6 @@ void testSimpleConfig() {
113114
assertEquals(5, config.intParam());
114115
}
115116

116-
@Test
117-
void testSimpleConfig_Disabled() {
118-
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", false);
119-
120-
// write config
121-
writeConfiguration(context, contentPage.getPath(), SimpleConfig.class.getName(),
122-
"stringParam", "value1",
123-
"intParam", 123);
124-
125-
// assert storage in page in /conf
126-
Page configPage = context.pageManager().getPage("/conf/test/site1/sling:configs/" + SimpleConfig.class.getName());
127-
assertNull(configPage);
128-
129-
// read config
130-
SimpleConfig config = contentPage.getContentResource().adaptTo(ConfigurationBuilder.class).as(SimpleConfig.class);
131-
assertEquals("value1", config.stringParam());
132-
assertEquals(123, config.intParam());
133-
}
134-
135117
@Test
136118
void testListConfig() {
137119
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", true);
@@ -453,4 +435,82 @@ void testListConfig_ResourceType() {
453435

454436
}
455437

438+
@Test
439+
void testSimpleConfig_Disabled() {
440+
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", false);
441+
doTestSimpleConfig_DisabledOrDenied();
442+
}
443+
444+
@Test
445+
void testSimpleConfig_Denied() {
446+
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", true,
447+
"configNameDenyList", new String[] { SimpleConfig.class.getName() });
448+
doTestSimpleConfig_DisabledOrDenied();
449+
}
450+
451+
void doTestSimpleConfig_DisabledOrDenied() {
452+
// write config
453+
writeConfiguration(context, contentPage.getPath(), SimpleConfig.class.getName(),
454+
"stringParam", "value1",
455+
"intParam", 123);
456+
457+
// assert storage in page in /conf
458+
Page configPage = context.pageManager().getPage("/conf/test/site1/sling:configs/" + SimpleConfig.class.getName());
459+
assertNull(configPage);
460+
461+
// read config
462+
SimpleConfig config = contentPage.getContentResource().adaptTo(ConfigurationBuilder.class).as(SimpleConfig.class);
463+
assertEquals("value1", config.stringParam());
464+
assertEquals(123, config.intParam());
465+
466+
// delete
467+
ConfigurationManager configManager = context.getService(ConfigurationManager.class);
468+
configManager.deleteConfiguration(contentPage.getContentResource(), SimpleConfig.class.getName());
469+
config = contentPage.getContentResource().adaptTo(ConfigurationBuilder.class).as(SimpleConfig.class);
470+
assertNull(config.stringParam());
471+
assertEquals(5, config.intParam());
472+
}
473+
474+
@Test
475+
void testListConfig_Disabled() {
476+
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", false);
477+
doTestListConfig_DisabledOrDenied();
478+
}
479+
480+
@Test
481+
void testListConfig_Denied() {
482+
context.registerInjectActivateService(PagePersistenceStrategy.class, "enabled", true,
483+
"configNameDenyList", new String[] { ListConfig.class.getName() });
484+
doTestListConfig_DisabledOrDenied();
485+
}
486+
487+
void doTestListConfig_DisabledOrDenied() {
488+
// write config
489+
writeConfigurationCollection(context, contentPage.getPath(), ListConfig.class.getName(), List.of(
490+
ImmutableValueMap.of("stringParam", "value1", "intParam", 123),
491+
ImmutableValueMap.of("stringParam", "value2", "intParam", 234)),
492+
ImmutableValueMap.of("sling:configCollectionInherit", true));
493+
494+
// assert storage in page in /conf
495+
Resource parentResource = context.resourceResolver().getResource("/conf/test/site1/sling:configs/" + ListConfig.class.getName());
496+
assertNotNull(parentResource);
497+
assertTrue(parentResource.getValueMap().get("sling:configCollectionInherit", false));
498+
499+
Resource configResource1 = context.resourceResolver().getResource("/conf/test/site1/sling:configs/" + ListConfig.class.getName() + "/item0");
500+
assertThat(configResource1, ResourceMatchers.props("stringParam", "value1", "intParam", 123));
501+
502+
Resource configResource2 = context.resourceResolver().getResource("/conf/test/site1/sling:configs/" + ListConfig.class.getName() + "/item1");
503+
assertThat(configResource2, ResourceMatchers.props("stringParam", "value2", "intParam", 234));
504+
505+
// read config
506+
List<ListConfig> configs = List.copyOf(contentPage.getContentResource().adaptTo(ConfigurationBuilder.class).asCollection(ListConfig.class));
507+
assertEquals(2, configs.size());
508+
ListConfig config1 = configs.get(0);
509+
assertEquals("value1", config1.stringParam());
510+
assertEquals(123, config1.intParam());
511+
ListConfig config2 = configs.get(1);
512+
assertEquals("value2", config2.stringParam());
513+
assertEquals(234, config2.intParam());
514+
}
515+
456516
}

0 commit comments

Comments
 (0)