Skip to main content
New Member
Jun 11, 2025 10:34 AM UTC
Solved

Context Aware Configuration Extension

Hello Community

 

We have a required to Customize CA Config where we need to have property in all the CA Configs and use this for our business functionality

 

Example as below. As shown isGlobalPropetry is repeating for N CAConfigs. Is there a way to have this available for any CA Config we will have for both present and the future ones?

public @interface CAConfig1 { @Property(label = "Some label 1", description = "Some description 1", order = 30) String property1(); @Property(label = "Global Property", description = "Some description", order = 50) boolean isGlobalPropetry() default true; } public @interface CAConfig2 { @Property(label = "Some label 2", description = "Some description 2", order = 30) String property2(); @Property(label = "Global Property", description = "Some description", order = 50) boolean isGlobalPropetry() default true; } public @interface CAConfig3 { @Property(label = "Some label 3", description = "Some description 3", order = 30) String property3(); @Property(label = "Global Property", description = "Some description", order = 50) boolean isGlobalPropetry() default true; } . . . . . . . public @interface CAConfigN { @Property(label = "Some label N", description = "Some description N", order = 30) String propertyN(); @Property(label = "Global Property", description = "Some description", order = 50) boolean isGlobalPropetry() default true; }

 

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
user70744Accepted solution
Level 3
Jun 16, 2025 7:09 AM UTC

hi @santoshsai 

Had a good idea from @arunpatidar where we can use filters to add a specific property to be available in all the CAs. Attached a sample code which worked. 

Thanks @arunpatidar 

import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.sling.engine.EngineConstants; import org.osgi.service.component.annotations.Component; import javax.json.*; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.CharArrayWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import static org.apache.sling.engine.EngineConstants.SLING_FILTER_PATTERN; import static org.apache.sling.engine.EngineConstants.SLING_FILTER_SCOPE; @Component(   service = Filter.class,   immediate = true,   name = "CaConfigFilter",   property = {     SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,     SLING_FILTER_PATTERN + "=" + "^/content/.*/jcr:content.configData.json"   } ) @Slf4j public class CaConfigFilter implements Filter {   private static final String GLOBAL_CONFIG_NAME = "isGlobalConfig";   @Override   public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)     throws IOException, ServletException {     final CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response);     chain.doFilter(request, wrappedResponse);     final String originalContent = wrappedResponse.toString();     String configSourcePath = StringUtils.EMPTY;     boolean globalConfigExists = false;     try (final JsonReader jsonReader = Json.createReader(new StringReader(originalContent))) {       final JsonObject jsonObject = jsonReader.readObject();       final JsonArrayBuilder updatedProperties = Json.createArrayBuilder();       for (final JsonValue val : jsonObject.getJsonArray("properties")) {         final JsonObject prop = val.asJsonObject();         final String name = prop.getString("name", StringUtils.EMPTY);         if (GLOBAL_CONFIG_NAME.equals(name)) {           globalConfigExists = true;           final JsonObjectBuilder builder = Json.createObjectBuilder();           for (final String key : prop.keySet()) {             if (!"metadata".equals(key)) {               builder.add(key, prop.get(key));             }           }           builder.add("metadata", createGlobalConfigMetadata());           updatedProperties.add(builder.build());         } else {           updatedProperties.add(prop);         }         if (StringUtils.isBlank(configSourcePath) && prop.containsKey("configSourcePath")) {           configSourcePath = prop.getString("configSourcePath");         }       }       if (!globalConfigExists) {         updatedProperties.add(createGlobalConfigProperty(configSourcePath));       }       final JsonObject modifiedJson = Json.createObjectBuilder(jsonObject)         .add("properties", updatedProperties)         .build();       response.setContentType("application/json");       response.getWriter().write(modifiedJson.toString());     } catch (final Exception e) {       log.error("Error modifying configData JSON: {}", e.getMessage(), e);       response.getWriter().write(originalContent); // fallback     }   }   private JsonObject createGlobalConfigProperty(final String configSourcePath) {     return Json.createObjectBuilder()       .add("name", GLOBAL_CONFIG_NAME)       .add("value", false)       .add("effectiveValue", false)       .add("configSourcePath", configSourcePath)       .add("inherited", false)       .add("overridden", false)       .add("metadata", createGlobalConfigMetadata())       .add("default", false)       .build();   }   private JsonObject createGlobalConfigMetadata() {     return Json.createObjectBuilder()       .add("type", "Boolean")       .add("defaultValue", false)       .add("label", "Global Configuration")       .add("description", "Indicates if this is a global configuration.")       .build();   }   private static class CharResponseWrapper extends HttpServletResponseWrapper {     private final CharArrayWriter charWriter = new CharArrayWriter();     public CharResponseWrapper(final HttpServletResponse response) {       super(response);     }     @Override     public PrintWriter getWriter() {       return new PrintWriter(charWriter);     }     @Override     public String toString() {       return charWriter.toString();     }   } }

. 

3 replies

SantoshSai
Community Advisor
Community Advisor
Jun 11, 2025 8:38 PM UTC

Hi @arung_,

To avoid repeating the same @Property (like isGlobalPropetry) across all Context-Aware Configs (CA Configs) in AEM, inheritance or composition would seem like a natural solution - Unfortunately, Java annotations do not support inheritance the same way classes do. That means you cannot extend or inherit annotation properties directly.

Translate
Santosh Sai
Level 3
Jun 12, 2025 8:02 AM UTC

Agree. and we were thinking if there is any good solution for this rather than repeating

Translate
user70744Accepted solution
Level 3
Jun 16, 2025 7:09 AM UTC

hi @santoshsai 

Had a good idea from @arunpatidar where we can use filters to add a specific property to be available in all the CAs. Attached a sample code which worked. 

Thanks @arunpatidar 

import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.sling.engine.EngineConstants; import org.osgi.service.component.annotations.Component; import javax.json.*; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.CharArrayWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import static org.apache.sling.engine.EngineConstants.SLING_FILTER_PATTERN; import static org.apache.sling.engine.EngineConstants.SLING_FILTER_SCOPE; @Component(   service = Filter.class,   immediate = true,   name = "CaConfigFilter",   property = {     SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,     SLING_FILTER_PATTERN + "=" + "^/content/.*/jcr:content.configData.json"   } ) @Slf4j public class CaConfigFilter implements Filter {   private static final String GLOBAL_CONFIG_NAME = "isGlobalConfig";   @Override   public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)     throws IOException, ServletException {     final CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response);     chain.doFilter(request, wrappedResponse);     final String originalContent = wrappedResponse.toString();     String configSourcePath = StringUtils.EMPTY;     boolean globalConfigExists = false;     try (final JsonReader jsonReader = Json.createReader(new StringReader(originalContent))) {       final JsonObject jsonObject = jsonReader.readObject();       final JsonArrayBuilder updatedProperties = Json.createArrayBuilder();       for (final JsonValue val : jsonObject.getJsonArray("properties")) {         final JsonObject prop = val.asJsonObject();         final String name = prop.getString("name", StringUtils.EMPTY);         if (GLOBAL_CONFIG_NAME.equals(name)) {           globalConfigExists = true;           final JsonObjectBuilder builder = Json.createObjectBuilder();           for (final String key : prop.keySet()) {             if (!"metadata".equals(key)) {               builder.add(key, prop.get(key));             }           }           builder.add("metadata", createGlobalConfigMetadata());           updatedProperties.add(builder.build());         } else {           updatedProperties.add(prop);         }         if (StringUtils.isBlank(configSourcePath) && prop.containsKey("configSourcePath")) {           configSourcePath = prop.getString("configSourcePath");         }       }       if (!globalConfigExists) {         updatedProperties.add(createGlobalConfigProperty(configSourcePath));       }       final JsonObject modifiedJson = Json.createObjectBuilder(jsonObject)         .add("properties", updatedProperties)         .build();       response.setContentType("application/json");       response.getWriter().write(modifiedJson.toString());     } catch (final Exception e) {       log.error("Error modifying configData JSON: {}", e.getMessage(), e);       response.getWriter().write(originalContent); // fallback     }   }   private JsonObject createGlobalConfigProperty(final String configSourcePath) {     return Json.createObjectBuilder()       .add("name", GLOBAL_CONFIG_NAME)       .add("value", false)       .add("effectiveValue", false)       .add("configSourcePath", configSourcePath)       .add("inherited", false)       .add("overridden", false)       .add("metadata", createGlobalConfigMetadata())       .add("default", false)       .build();   }   private JsonObject createGlobalConfigMetadata() {     return Json.createObjectBuilder()       .add("type", "Boolean")       .add("defaultValue", false)       .add("label", "Global Configuration")       .add("description", "Indicates if this is a global configuration.")       .build();   }   private static class CharResponseWrapper extends HttpServletResponseWrapper {     private final CharArrayWriter charWriter = new CharArrayWriter();     public CharResponseWrapper(final HttpServletResponse response) {       super(response);     }     @Override     public PrintWriter getWriter() {       return new PrintWriter(charWriter);     }     @Override     public String toString() {       return charWriter.toString();     }   } }

. 

Translate