diff --git a/CHANGELOG.md b/CHANGELOG.md
index 785f222695..571a10cd0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,8 +10,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
## Unreleased ([details][unreleased changes details])
+## 6.1.0 - 2023-09-08
+
+## 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
+- #3147 - Fixed setting initial content-type when importing CFs from a spreadsheet
- #3040 - Fixed bug where namespaced multi-fields would have the namespace 2 times
- #3140 - Fixed issue where malformed MCP process nodes can cause a NPE that breaks the entire MPC reporting UI. Now displays more friendly values in UI to help remove the invalid nodes.
- #3150 - Support for case-insensitive redirect rules ( [NC] flag equivalent of apache)
diff --git a/all/pom.xml b/all/pom.xml
index 316f7f5b33..098119bbd4 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT
diff --git a/bundle/pom.xml b/bundle/pom.xml
index 43f83c3c3e..c0d2b8c9ec 100644
--- a/bundle/pom.xml
+++ b/bundle/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT
diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java
new file mode 100644
index 0000000000..e92f23dc46
--- /dev/null
+++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTagger.java
@@ -0,0 +1,254 @@
+/*-
+ * #%L
+ * ACS AEM Commons Bundle
+ * %%
+ * 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.
+ * #L%
+ */
+package com.adobe.acs.commons.mcp.impl.processes;
+
+import com.adobe.acs.commons.fam.ActionManager;
+import com.adobe.acs.commons.mcp.ProcessDefinition;
+import com.adobe.acs.commons.mcp.ProcessInstance;
+import com.adobe.acs.commons.mcp.form.FileUploadComponent;
+import com.adobe.acs.commons.mcp.form.FormField;
+import com.adobe.acs.commons.mcp.model.GenericBlobReport;
+import com.adobe.acs.commons.mcp.util.StringUtil;
+import com.day.cq.tagging.Tag;
+import com.day.cq.wcm.api.Page;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * The type Bulk page tagger.
+ */
+public class BulkPageTagger extends ProcessDefinition implements Serializable {
+ private static final Logger log = LoggerFactory.getLogger(BulkPageTagger.class);
+ private static final long serialVersionUID = 798823856839772874L;
+
+ /**
+ * The constant NAME.
+ */
+ public static final String NAME = "Bulk Page Tagger";
+
+ /**
+ * The Excel file.
+ */
+ @FormField(
+ name = "Excel File",
+ description = "Provide the .xlsx file that defines the content pages and the corresponding cq:tags to be added on the pages",
+ component = FileUploadComponent.class,
+ options = {"mimeTypes=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "required"}
+ )
+ public transient InputStream excelFile = null;
+
+
+ @Override
+ public void init() throws RepositoryException {
+ // Nothing to be done here.
+
+ }
+
+
+ @Override
+ public void buildProcess(ProcessInstance instance, ResourceResolver rr) throws LoginException {
+ report.setName(instance.getName());
+ instance.getInfo().setDescription("Bulk Tag AEM content Pages");
+ instance.defineCriticalAction("Parse Excel File", rr, this::parseExcel);
+ instance.defineCriticalAction("Add Tags to Content Pages", rr, this::tagPages);
+
+ }
+
+
+ /**
+ * The Page tag mapping dataStructure.
+ */
+ transient volatile HashMap pageTagMapping = new LinkedHashMap<>();
+
+ /**
+ * Parse input excel.
+ *
+ * @param manager the manager
+ * @throws Exception the exception
+ */
+ @SuppressWarnings("squid:S112")
+ public void parseExcel(ActionManager manager) throws Exception {
+ manager.withResolver(rr -> {
+ final XSSFWorkbook workbook = new XSSFWorkbook(excelFile);
+ final XSSFSheet sheet = workbook.getSheetAt(0);
+
+ final Iterator rows = sheet.rowIterator();
+ final String tagsRootPath = new TagCreator.TagRootResolver(rr).getTagsLocationPath();
+
+
+ if (tagsRootPath == null) {
+ recordAction(ReportRowSatus.FAILED_TO_PARSE,
+ "Abandoning Tag parsing. Unable to determine AEM Tags root (/content/cq:tags vs /etc/tags). Please ensure the path exists and is accessible by the user running Tag Creator.", "N/A");
+ return;
+ }
+
+ while (rows.hasNext()) {
+ final Row row = rows.next();
+ if (row.getCell(0) == null) {
+ break;
+ }
+ if (row.getRowNum() != 0 && row.getCell(0) != null) {
+ pageTagMapping.put(row.getCell(0).getStringCellValue(), row.getCell(1).getStringCellValue());
+ }
+ }
+
+ });
+
+ }
+
+
+ /**
+ * Tag pages from the excel file with cq:tags.
+ *
+ * @param manager the manager
+ * @throws Exception the exception
+ */
+ @SuppressWarnings("squid:S112")
+ public void tagPages(ActionManager manager) throws Exception {
+
+ manager.withResolver(rr -> {
+
+ pageTagMapping.forEach((key, value) -> {
+ BulkPageTagger.ReportRowSatus status;
+ Resource resource = rr.getResource(key);
+ if (resource != null) {
+ Page page = resource.adaptTo(Page.class);
+ if (page != null) {
+ Tag[] existingPageTags = page.getTags();
+ String[] tagIds = Stream.of(existingPageTags)
+ .map(Tag::getTagID)
+ .toArray(String[]::new);
+ Set updatedTags = Arrays.stream(value.split("[;\n]"))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+ updatedTags.addAll(Arrays.asList(tagIds));
+ String[] updatedTagsArray = updatedTags.stream().toArray(String[]::new);
+
+ ModifiableValueMap properties = page.getContentResource().adaptTo(ModifiableValueMap.class);
+ properties.put(com.day.cq.tagging.TagConstants.PN_TAGS, updatedTagsArray);
+ try {
+ rr.commit();
+ status = ReportRowSatus.UPDATED_EXISTING;
+ recordAction(status, page.getPath(), Arrays.toString(updatedTagsArray));
+ } catch (PersistenceException e) {
+ status = ReportRowSatus.FAILED_TO_UPDATE;
+ recordAction(status, page.getPath(), Arrays.toString(updatedTagsArray));
+ log.error(String.format("Unable to add tags to page with page path - %s ", page.getPath()));
+ }
+
+
+ }
+
+ }
+
+ });
+ });
+ }
+
+
+ /**
+ * Reporting
+ **/
+
+
+ private final transient GenericBlobReport report = new GenericBlobReport();
+
+ private final transient ArrayList> reportRows = new ArrayList<>();
+
+ private enum ReportColumns {
+ /**
+ * Status report columns.
+ */
+ STATUS,
+ /**
+ * Page path report columns.
+ */
+ PAGE_PATH,
+ /**
+ * Tags array report columns.
+ */
+ TAGS_ARRAY
+ }
+
+ /**
+ * The enum Report row satus.
+ */
+ public enum ReportRowSatus {
+ /**
+ * Created report row satus.
+ */
+ CREATED,
+ /**
+ * Updated existing report row satus.
+ */
+ UPDATED_EXISTING,
+ /**
+ * Failed to parse report row satus.
+ */
+ FAILED_TO_PARSE,
+ /**
+ * Failed to update report row satus.
+ */
+ FAILED_TO_UPDATE
+ }
+
+
+ private void recordAction(BulkPageTagger.ReportRowSatus status, String pagePath, String tags) {
+ final EnumMap row = new EnumMap<>(BulkPageTagger.ReportColumns.class);
+
+ row.put(BulkPageTagger.ReportColumns.STATUS, StringUtil.getFriendlyName(status.name()));
+ row.put(ReportColumns.PAGE_PATH, pagePath);
+ row.put(ReportColumns.TAGS_ARRAY, tags);
+
+ reportRows.add(row);
+ }
+
+
+ @Override
+ public void storeReport(ProcessInstance instance, ResourceResolver rr) throws RepositoryException, PersistenceException {
+ report.setRows(reportRows, BulkPageTagger.ReportColumns.class);
+ report.persist(rr, instance.getPath() + "/jcr:content/report");
+ }
+
+
+}
diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java
new file mode 100644
index 0000000000..0c9ba7c79d
--- /dev/null
+++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerFactory.java
@@ -0,0 +1,39 @@
+/*-
+ * #%L
+ * ACS AEM Commons Bundle
+ * %%
+ * 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.
+ * #L%
+ */
+package com.adobe.acs.commons.mcp.impl.processes;
+
+import com.adobe.acs.commons.mcp.ProcessDefinitionFactory;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+
+@Component
+@Service(ProcessDefinitionFactory.class)
+public class BulkPageTaggerFactory extends ProcessDefinitionFactory {
+
+ @Override
+ public String getName() {
+ return BulkPageTagger.NAME;
+ }
+
+ @Override
+ protected BulkPageTagger createProcessDefinitionInstance() {
+ return new BulkPageTagger();
+ }
+}
diff --git a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java
index 2510cf8a04..efe48f9ff5 100644
--- a/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java
+++ b/bundle/src/main/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImport.java
@@ -33,7 +33,6 @@
import com.adobe.cq.dam.cfm.FragmentTemplate;
import com.day.cq.commons.jcr.JcrConstants;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -48,22 +47,17 @@
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Import a series of content fragments from a spreadsheet
*/
public class ContentFragmentImport extends ProcessDefinition {
- private static final Logger LOG = LoggerFactory.getLogger(ContentFragmentImport.class);
-
public enum ReportColumns {
ITEM, ACTION, DESCRIPTION, COUNT
}
@@ -313,8 +307,14 @@ private void setContentElements(ContentFragment cf, Map row, ContentElement conte
protected ContentFragment getOrCreateFragment(Resource parent, Resource template, String name, String title) throws ContentFragmentException {
Resource fragmentResource = parent.getChild(name);
if (fragmentResource == null) {
- try {
- FragmentTemplate fragmentTemplate = template.adaptTo(FragmentTemplate.class);
-// TODO: Replace this reflection hack with the proper method once ACS Commons doesn't support 6.2 anymore
- return (ContentFragment) MethodUtils.invokeMethod(fragmentTemplate, "createFragment", parent, name, title);
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
- LOG.error("Unable to call createFragment method -- Is this 6.3 or newer?", ex);
- return null;
- }
+ FragmentTemplate fragmentTemplate = template.adaptTo(FragmentTemplate.class);
+ return fragmentTemplate.createFragment(parent, name, title);
} else {
return fragmentResource.adaptTo(ContentFragment.class);
}
diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java
index a0b5b24808..a99caf95ba 100644
--- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java
+++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/HierarchicalPageProperty.java
@@ -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;
@@ -39,14 +40,9 @@
@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.
@@ -54,6 +50,12 @@
*/
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.
diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java
new file mode 100644
index 0000000000..4e2f73a20c
--- /dev/null
+++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/annotation/PageProperty.java
@@ -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;
+
+}
diff --git a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java
index 37ef6c49ff..706784875c 100644
--- a/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java
+++ b/bundle/src/main/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjector.java
@@ -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;
@@ -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;
}
@@ -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);
+ }
}
}
diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java
new file mode 100644
index 0000000000..3e08035a41
--- /dev/null
+++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/BulkPageTaggerTest.java
@@ -0,0 +1,90 @@
+/*-
+ * #%L
+ * ACS AEM Commons Bundle
+ * %%
+ * 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.
+ * #L%
+ */
+package com.adobe.acs.commons.mcp.impl.processes;
+
+import com.adobe.acs.commons.fam.ActionManager;
+import com.adobe.acs.commons.functions.CheckedConsumer;
+import io.wcm.testing.mock.aem.junit.AemContext;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BulkPageTaggerTest {
+
+ @Rule
+ public final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);
+
+ private BulkPageTagger bulkPageTagger;
+
+ @Mock
+ private ActionManager actionManager;
+
+ @Before
+ public void setUp() throws Exception {
+ bulkPageTagger = new BulkPageTagger();
+ bulkPageTagger.excelFile = getClass().getResourceAsStream("/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx");
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ CheckedConsumer method = (CheckedConsumer) invocation.getArguments()[0];
+ method.accept(context.resourceResolver());
+ return null;
+ }
+ }).when(actionManager).withResolver(any(CheckedConsumer.class));
+
+ }
+
+ @Test
+ public void testParseExcel() throws Exception {
+
+ final String tagsRootPath = com.day.cq.tagging.TagConstants.TAG_ROOT_PATH;
+ context.create().resource(tagsRootPath, JcrConstants.JCR_PRIMARYTYPE, "sling:Folder");
+ context.resourceResolver().commit();
+ bulkPageTagger.parseExcel(actionManager);
+
+ final int expected = 9;
+ assertEquals(expected,bulkPageTagger.pageTagMapping.size() );
+ }
+
+ @Test
+ public void testTagPages() throws Exception {
+
+ bulkPageTagger.parseExcel(actionManager);
+ context.create().page("/content/wknd/language-masters/en/about-us");
+ context.create().resource("/content/wknd/language-masters/en/about-us/jcr:content",
+ JcrConstants.JCR_PRIMARYTYPE,
+ "cq:pagecontent","cq:tags","wknd-shared:activity/bulktagtest3;wknd-shared:activity/bulktagtest10");
+ bulkPageTagger.tagPages(actionManager);
+
+ }
+}
diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java
index 07a1e4c13b..038ded4657 100644
--- a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java
+++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/ContentFragmentImportTest.java
@@ -28,8 +28,6 @@
import java.util.Date;
import java.time.OffsetDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
diff --git a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java
index 8c7698bf3e..82cc8676e9 100644
--- a/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java
+++ b/bundle/src/test/java/com/adobe/acs/commons/mcp/impl/processes/cfi/MockContentFragment.java
@@ -37,6 +37,10 @@
import org.apache.sling.api.resource.Resource;
import org.jetbrains.annotations.NotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
/**
* Incomplete mock that provides just enough for basic testing
*/
@@ -47,6 +51,14 @@ public class MockContentFragment implements ContentFragment {
String path;
HashMap elements = new HashMap<>();
HashMap metadata = new HashMap<>();
+ FragmentTemplate template;
+
+ public MockContentFragment(){
+ template = mock(FragmentTemplate.class);
+ ElementTemplate elementTemplate = mock(ElementTemplate.class);
+ doReturn("text/html").when(elementTemplate).getInitialContentType();
+ doReturn(elementTemplate).when(template).getForElement(any(ContentElement.class));
+ }
@Override
public Iterator getElements() {
@@ -114,7 +126,7 @@ public Iterator listAllVariations() {
@Override
public FragmentTemplate getTemplate() {
- return null;
+ return template;
}
@Override
diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java
index fc0e57ecc9..2ad5625cc3 100644
--- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java
+++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/HierarchicalPagePropertyInjectorTest.java
@@ -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;
@@ -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 {
@@ -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 {
@@ -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());
}
diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java
index 4365350c2b..b38acaebb2 100644
--- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java
+++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestHierarchicalPagePropertiesModel.java
@@ -23,7 +23,9 @@
public interface TestHierarchicalPagePropertiesModel {
- String getPropertyString();
+ String getPagePropertyString();
+
+ String getHierarchicalPagePropertyString();
String getUndefinedProperty();
diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java
new file mode 100644
index 0000000000..757d52cfc2
--- /dev/null
+++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/TestPagePropertiesModel.java
@@ -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();
+
+}
diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java
index b786963cdb..ae255f5284 100644
--- a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java
+++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestHierarchicalPagePropertiesModelModelImpl.java
@@ -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
@@ -63,7 +66,12 @@ public class TestHierarchicalPagePropertiesModelModelImpl implements TestHierarc
@Override
- public String getPropertyString() {
+ public String getPagePropertyString() {
+ return pagePropertyString;
+ }
+
+ @Override
+ public String getHierarchicalPagePropertyString() {
return hierarchicalPagePropertyString;
}
diff --git a/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java
new file mode 100644
index 0000000000..7faa5d76c4
--- /dev/null
+++ b/bundle/src/test/java/com/adobe/acs/commons/models/injectors/impl/model/impl/TestPagePropertiesModelModelImpl.java
@@ -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;
+ }
+
+}
diff --git a/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx b/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx
new file mode 100644
index 0000000000..e62257641d
Binary files /dev/null and b/bundle/src/test/resources/com/adobe/acs/commons/mcp/impl/processes/bulkPageTagger.xlsx differ
diff --git a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json
index 6a80e34a7d..6baabc8f61 100644
--- a/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json
+++ b/bundle/src/test/resources/com/adobe/acs/commons/models/injectors/impl/we-retail-pages.json
@@ -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": [
@@ -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",
diff --git a/oakpal-checks/pom.xml b/oakpal-checks/pom.xml
index 0259a6bdfe..75c32575f5 100644
--- a/oakpal-checks/pom.xml
+++ b/oakpal-checks/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT
diff --git a/pom.xml b/pom.xml
index df76f9f47d..167e1cbffd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT
pom
ACS AEM Commons - Reactor Project
@@ -88,7 +88,7 @@
1.8
1.8
- 1689084806
+ 1694204679
diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml
index 09a79d924d..5a036d06cb 100644
--- a/ui.apps/pom.xml
+++ b/ui.apps/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT
diff --git a/ui.content/pom.xml b/ui.content/pom.xml
index 861c9c86b1..45ff9b0550 100644
--- a/ui.content/pom.xml
+++ b/ui.content/pom.xml
@@ -25,7 +25,7 @@
com.adobe.acs
acs-aem-commons
- 6.0.15-SNAPSHOT
+ 6.1.1-SNAPSHOT