Skip to content

Commit

Permalink
Add page property injection (Adobe-Consulting-Services#3160)
Browse files Browse the repository at this point in the history
* Add page property injection
---------

Co-authored-by: Roy Teeuwen <[email protected]>
  • Loading branch information
2 people authored and YegorKozlov committed Oct 19, 2023
1 parent 790a32d commit 2e90bf6
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 21 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
## Unreleased ([details][unreleased changes details])
- #3147 - Fixed setting initial content-type when importing CFs from a spreadsheet

#3170 - Added a new MCP tool to bulk tag AEM content pages via an Excel file input.

## Added

- #3159 - Add PageProperty annotation for Sling Models
- #3170 - Added a new MCP tool to bulk tag AEM content pages via an Excel file input.

## Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.adobe.acs.commons.models.injectors.annotation;


import com.adobe.acs.commons.models.injectors.impl.HierarchicalPagePropertyInjector;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
Expand All @@ -39,21 +40,22 @@
@Target({METHOD, FIELD, PARAMETER})
@Retention(RUNTIME)
@InjectAnnotation
@Source(HierarchicalPageProperty.SOURCE)
@Source(HierarchicalPagePropertyInjector.SOURCE)
public @interface HierarchicalPageProperty {

/**
* Source value used for this annotation.
* @see Source
*/
String SOURCE = "hierarchical-page-property";

/**
* Specifies the name of the value from the value map to take.
* If empty, then the name is derived from the method or field.
*/
String value() default StringUtils.EMPTY;

/**
* Specifies if it should use the hierarchy to search for the page property.
* If false, it will only look at the current page.
*/
boolean inherit() default true;

/**
* if set to REQUIRED injection is mandatory, if set to OPTIONAL injection is optional, in case of DEFAULT
* the standard annotations ({@link org.apache.sling.models.annotations.Optional}, {@link org.apache.sling.models.annotations.Required}) are used.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* ACS AEM Commons
*
* Copyright (C) 2013 - 2023 Adobe
*
* 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.
*/
package com.adobe.acs.commons.models.injectors.annotation;


import com.adobe.acs.commons.models.injectors.impl.HierarchicalPagePropertyInjector;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Injects a page property.
* Note: not supported by the javax.Inject annotation because of performance reasons. Only direct annotation is supported.
*/
@Target({METHOD, FIELD, PARAMETER})
@Retention(RUNTIME)
@InjectAnnotation
@Source(HierarchicalPagePropertyInjector.SOURCE)
public @interface PageProperty {


/**
* Specifies the name of the value from the value map to take.
* If empty, then the name is derived from the method or field.
*/
String value() default StringUtils.EMPTY;


/**
* if set to REQUIRED injection is mandatory, if set to OPTIONAL injection is optional, in case of DEFAULT
* the standard annotations ({@link org.apache.sling.models.annotations.Optional}, {@link org.apache.sling.models.annotations.Required}) are used.
* If even those are not available the default injection strategy defined on the {@link org.apache.sling.models.annotations.Model} applies.
* Default value = DEFAULT.
*/
InjectionStrategy injectionStrategy() default InjectionStrategy.DEFAULT;

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
package com.adobe.acs.commons.models.injectors.impl;

import com.adobe.acs.commons.models.injectors.annotation.HierarchicalPageProperty;
import com.adobe.acs.commons.models.injectors.annotation.PageProperty;
import com.adobe.acs.commons.util.impl.ReflectionUtil;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.wcm.api.Page;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Source;
import org.apache.sling.models.spi.DisposalCallbackRegistry;
import org.apache.sling.models.spi.Injector;
import org.osgi.framework.Constants;
Expand All @@ -42,15 +44,22 @@
)
public class HierarchicalPagePropertyInjector implements Injector {

/**
* Source value used for injector
*
* @see Source
*/
public static final String SOURCE = "hierarchical-page-property";

@Override
public String getName() {
return HierarchicalPageProperty.SOURCE;
return SOURCE;
}

public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
DisposalCallbackRegistry callbackRegistry) {

if (!element.isAnnotationPresent(HierarchicalPageProperty.class)) {
if (!(element.isAnnotationPresent(HierarchicalPageProperty.class) || element.isAnnotationPresent(PageProperty.class))) {
//skipping javax.Inject for performance reasons. Only supports direct injection.
return null;
}
Expand All @@ -59,8 +68,12 @@ public Object getValue(Object adaptable, String name, Type declaredType, Annotat
if (currentResource != null) {
Resource adaptableRes = lookUpFromPage(currentResource);
if (adaptableRes != null) {
InheritanceValueMap inheritanceValueMap = new HierarchyNodeInheritanceValueMap(adaptableRes);
return ReflectionUtil.convertValueMapValue(inheritanceValueMap, name, declaredType);
if (element.isAnnotationPresent(PageProperty.class) || !element.getAnnotation(HierarchicalPageProperty.class).inherit()) {
return ReflectionUtil.convertValueMapValue(adaptableRes.getValueMap(), name, declaredType);
} else {
InheritanceValueMap inheritanceValueMap = new HierarchyNodeInheritanceValueMap(adaptableRes);
return ReflectionUtil.convertValueMapValue(inheritanceValueMap, name, declaredType);
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
*/
package com.adobe.acs.commons.models.injectors.impl;

import com.adobe.acs.commons.models.injectors.annotation.HierarchicalPageProperty;
import com.adobe.acs.commons.models.injectors.annotation.impl.HierarchicalPagePropertyAnnotationProcessorFactory;
import com.adobe.acs.commons.models.injectors.impl.model.TestHierarchicalPagePropertiesModel;
import com.adobe.acs.commons.models.injectors.impl.model.TestPagePropertiesModel;
import com.adobe.acs.commons.models.injectors.impl.model.impl.TestHierarchicalPagePropertiesModelModelImpl;
import com.adobe.acs.commons.models.injectors.impl.model.impl.TestPagePropertiesModelModelImpl;
import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.spi.Injector;
Expand All @@ -32,8 +33,7 @@
import org.mockito.InjectMocks;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.*;

@RunWith(MockitoJUnitRunner.class)
public class HierarchicalPagePropertyInjectorTest {
Expand All @@ -43,7 +43,8 @@ public class HierarchicalPagePropertyInjectorTest {

@InjectMocks
private HierarchicalPagePropertyInjector injector;
private TestHierarchicalPagePropertiesModel adapted;
private TestHierarchicalPagePropertiesModel hierarchicalModel;
private TestPagePropertiesModel pageModel;

@Before
public void setUp() throws Exception {
Expand All @@ -53,19 +54,24 @@ public void setUp() throws Exception {
context.registerService(Injector.class, injector);
context.registerService(StaticInjectAnnotationProcessorFactory.class, new HierarchicalPagePropertyAnnotationProcessorFactory());
context.addModelsForClasses(TestHierarchicalPagePropertiesModelModelImpl.class);
context.addModelsForClasses(TestPagePropertiesModelModelImpl.class);

Resource adaptable = context.request().getResource();
adapted = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class);
hierarchicalModel = adaptable.adaptTo(TestHierarchicalPagePropertiesModel.class);
pageModel = adaptable.adaptTo(TestPagePropertiesModel.class);
}

@Test
public void test_name() {
assertEquals(HierarchicalPageProperty.SOURCE, injector.getName());
assertEquals(HierarchicalPagePropertyInjector.SOURCE, injector.getName());
}

@Test
public void test() {
assertNotNull(adapted);
assertNotNull(hierarchicalModel);
assertEquals("inherited!", hierarchicalModel.getHierarchicalPagePropertyString());
assertNull(pageModel.getHierarchicalPagePropertyString());
assertEquals("not inherited", hierarchicalModel.getPagePropertyString());
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@

public interface TestHierarchicalPagePropertiesModel {

String getPropertyString();
String getPagePropertyString();

String getHierarchicalPagePropertyString();

String getUndefinedProperty();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* ACS AEM Commons
*
* Copyright (C) 2013 - 2023 Adobe
*
* 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.
*/
package com.adobe.acs.commons.models.injectors.impl.model;


public interface TestPagePropertiesModel {

String getPagePropertyString();

String getHierarchicalPagePropertyString();

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@
)
public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarchicalPagePropertiesModel {

@HierarchicalPageProperty
private String pagePropertyString;

@HierarchicalPageProperty
private String hierarchicalPagePropertyString;

@HierarchicalPageProperty("hierarchicalPagePropertyBoolean")
@HierarchicalPageProperty(value = "hierarchicalPagePropertyBoolean", inherit = false)
private boolean hierarchicalPagePropertyBoolean;

@HierarchicalPageProperty
Expand All @@ -63,7 +66,12 @@ public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarc


@Override
public String getPropertyString() {
public String getPagePropertyString() {
return pagePropertyString;
}

@Override
public String getHierarchicalPagePropertyString() {
return hierarchicalPagePropertyString;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* ACS AEM Commons
*
* Copyright (C) 2013 - 2023 Adobe
*
* 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.
*/
package com.adobe.acs.commons.models.injectors.impl.model.impl;

import com.adobe.acs.commons.models.injectors.annotation.PageProperty;
import com.adobe.acs.commons.models.injectors.impl.model.TestPagePropertiesModel;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;

@Model(
adapters = TestPagePropertiesModel.class,
adaptables = {SlingHttpServletRequest.class, Resource.class},
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class TestPagePropertiesModelModelImpl implements TestPagePropertiesModel {

@PageProperty
private String hierarchicalPagePropertyString;
@PageProperty
private String pagePropertyString;

@Override
public String getPagePropertyString() {
return pagePropertyString;
}

@Override
public String getHierarchicalPagePropertyString() {
return hierarchicalPagePropertyString;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"cq:template": "/conf/we-retail/settings/wcm/templates/hero-page",
"cq:designPath": "/etc/designs/acs-commons",
"hierarchicalPagePropertyString": "inherited!",
"pagePropertyString": "inherited!",
"hierarchicalPagePropertyBoolean": true,
"hierarchicalPagePropertyInteger": 11,
"hierarchicalPagePropertyMultiValueInteger": [
Expand Down Expand Up @@ -168,6 +169,8 @@
"cq:lastModified": "Tue Nov 06 2018 11:00:39 GMT+0100",
"sling:resourceType": "weretail/components/structure/page",
"cq:lastModifiedBy": "admin",
"pagePropertyString": "not inherited",
"hierarchicalPagePropertyBoolean": false,
"root": {
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "wcm/foundation/components/responsivegrid",
Expand Down

0 comments on commit 2e90bf6

Please sign in to comment.