Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ Install hooks have no limitations when being used with the AEMaaCS SDK Quickstar
Content packages of type `mixed` are allowed to have both mutable and immutable nodes. AEMaaCS will only ever install the immutable part of it. The mutable part won't be installed as that cannot be successful (due to missing write access at the time of installation).
Further details at <https://experienceleague.adobe.com/docs/experience-manager-cloud-service/implementing/deploying/overview.html?lang=en#deploying-content-packages-via-cloud-manager-and-package-manager>.

## Enforce Oak index definitions of type `lucene`
## Enforce Oak index definitions of type `lucene` with `compatVersion` set to 2

Currently only Oak index definitions of type `lucene` are supported in AEMaaCS. Further details in <https://experienceleague.adobe.com/docs/experience-manager-cloud-service/operations/indexing.html?lang=en#changes-in-aem-as-a-cloud-service>.
Currently only Oak index definitions of type `lucene` with property `compatVersion` set to the (Long) value `2` are supported in AEMaaCS. Further details in <https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/operations/indexing#current-limitations>.

## Follow naming policy for Oak index definition node names

Expand Down
12 changes: 5 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>

<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<!-- http://metainf-services.kohsuke.org/index.html -->
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
Expand Down Expand Up @@ -112,12 +116,6 @@
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>${jackrabbit.version}</version>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-jackrabbit-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.regex.Pattern;

import javax.jcr.PropertyType;

import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
import org.apache.jackrabbit.vault.packaging.PackageType;
import org.apache.jackrabbit.vault.util.Constants;
import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.apache.jackrabbit.vault.util.DocViewProperty2;
import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
import org.apache.jackrabbit.vault.validation.spi.MetaInfPathValidator;
import org.apache.jackrabbit.vault.validation.spi.NodeContext;
Expand All @@ -48,8 +52,9 @@ public class AemCloudValidator implements NodePathValidator, MetaInfPathValidato
static final String VIOLATION_MESSAGE_LIBS_NODES = "Nodes below '/libs' may be overwritten by future product upgrades. Rather use '/apps'. Further details at https://experienceleague.adobe.com/docs/experience-manager-cloud-service/implementing/developing/full-stack/overlays.html?lang=en#developing";
static final String VIOLATION_MESSAGE_MUTABLE_NODES_IN_MIXED_PACKAGE = "Mutable nodes in mixed package types are not installed!";
static final String VIOLATION_MESSAGE_MUTABLE_NODES_AND_IMMUTABLE_NODES_IN_SAME_PACKAGE = "Mutable and immutable nodes must not be mixed in the same package. You must separate those into two packages and give them both a dedicated package type!";
static final String VIOLATION_MESSAGE_NON_LUCENE_TYPE_INDEX_DEFINITION = "Only oak:QueryIndexDefinitions of type='lucene' are supported in AEMaaCS but found type='%s'. Compare with https://experienceleague.adobe.com/docs/experience-manager-cloud-service/operations/indexing.html?lang=en#changes-in-aem-as-a-cloud-service";

static final String VIOLATION_MESSAGE_NON_LUCENE_TYPE_INDEX_DEFINITION = "Only oak:QueryIndexDefinitions of type='lucene' are supported in AEMaaCS but found type='%s'. Compare with https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/operations/indexing#current-limitations";
static final String VIOLATION_MESSAGE_INVALID_COMPAT_VERSION_IN_INDEX_DEFINITION = "The compatVersion property of an oak:QueryIndexDefinition must be set to the Long value '2' but found '%s'. Compare with https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/operations/indexing#current-limitations";

// this path is relative to META-INF
private static final Path INSTALL_HOOK_PATH = Paths.get(Constants.VAULT_DIR, Constants.HOOKS_DIR);
/**
Expand Down Expand Up @@ -78,6 +83,7 @@ public class AemCloudValidator implements NodePathValidator, MetaInfPathValidato

private static final int MAX_NUM_VIOLATIONS_PER_TYPE = 5;
private static final Name PN_TYPE = NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "type");
private static final Name PN_COMPAT_VERSION = NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "compatVersion");
private int numVarNodeViolations = 0;
private int numLibNodeViolations = 0;
private int numMutableNodeViolations = 0;
Expand Down Expand Up @@ -212,6 +218,12 @@ static boolean isPackagePathInstalledConditionally(String runMode, Path packageR
if (!"lucene".equals(indexType)) {
messages.add(new ValidationMessage(defaultSeverity,
String.format(VIOLATION_MESSAGE_NON_LUCENE_TYPE_INDEX_DEFINITION, indexType)));
} else {
Optional<DocViewProperty2> compatVersionProperty = node.getProperty(PN_COMPAT_VERSION);
if (!compatVersionProperty.isPresent() || compatVersionProperty.get().getType() != PropertyType.LONG || !compatVersionProperty.get().getStringValue().orElse("").equals("2")) {
messages.add(new ValidationMessage(defaultSeverity,
String.format(VIOLATION_MESSAGE_INVALID_COMPAT_VERSION_IN_INDEX_DEFINITION, compatVersionProperty.map(p -> p.formatValue()).orElse("not set"))));
}
}
// check node name (jcr qualified name as contained in the path)
String qualifiedName = Text.getName(nodeContext.getNodePath());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package biz.netcentric.filevault.validator.aem.cloud;

import static org.junit.jupiter.api.Assertions.assertEquals;

/*-
* #%L
* AEM Cloud Validator
Expand All @@ -20,6 +22,8 @@
import java.util.List;
import java.util.Optional;

import javax.jcr.PropertyType;

import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
Expand All @@ -30,11 +34,11 @@
import org.apache.jackrabbit.vault.validation.spi.ValidationMessage;
import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
import org.apache.jackrabbit.vault.validation.spi.util.NodeContextImpl;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AemCloudValidatorTest {

@Test
Expand Down Expand Up @@ -99,12 +103,13 @@ void testValidIndexDefinitions() {
Collection<ValidationMessage> messages = new ArrayList<>();
List<DocViewProperty2> properties = Arrays.asList(
new DocViewProperty2(NameConstants.JCR_PRIMARYTYPE, "oak:QueryIndexDefinition"),
new DocViewProperty2(NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "type"), "lucene"));
new DocViewProperty2(NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "type"), "lucene"),
new DocViewProperty2(NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "compatVersion"), "2", PropertyType.LONG));
// valid lucene index definition
NodeContext context = new NodeContextImpl("/oak:index/prefix.myindex-1-custom-1", Paths.get("_oak_index/test"),Paths.get("./jcr_root"));
DocViewNode2 node = new DocViewNode2(NameConstants.JCR_ROOT, properties);
Optional.ofNullable(validator.validate(node, context, true)).ifPresent(messages::addAll);
Assertions.assertTrue(messages.isEmpty());
MatcherAssert.assertThat(messages, Matchers.empty());
context = new NodeContextImpl("/oak:index/productindex-1-custom-1", Paths.get("_oak_index/test"),Paths.get("./jcr_root"));
Optional.ofNullable(validator.validate(node, context, true)).ifPresent(messages::addAll);
Assertions.assertTrue(messages.isEmpty());
Expand All @@ -117,11 +122,14 @@ void testInvalidLuceneIndexDefinitions() {
List<DocViewProperty2> properties = Arrays.asList(
new DocViewProperty2(NameConstants.JCR_PRIMARYTYPE, "oak:QueryIndexDefinition"),
new DocViewProperty2(NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "type"), "lucene"));
// invalid name and also compatVersion not set
NodeContext context = new NodeContextImpl("/oak:index/myindex", Paths.get("_oak_index/test"),Paths.get("./jcr_root"));
DocViewNode2 node = new DocViewNode2(NameConstants.JCR_ROOT, properties);
Optional.ofNullable(validator.validate(node, context, true)).ifPresent(messages::addAll);
assertEquals(1, messages.size());
assertEquals(String.format(AemCloudValidator.VIOLATION_MESSAGE_INVALID_INDEX_DEFINITION_NODE_NAME, "myindex"), messages.iterator().next().getMessage());
MatcherAssert.assertThat(messages, Matchers.containsInAnyOrder(
new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(AemCloudValidator.VIOLATION_MESSAGE_INVALID_INDEX_DEFINITION_NODE_NAME, "myindex")),
new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(AemCloudValidator.VIOLATION_MESSAGE_INVALID_COMPAT_VERSION_IN_INDEX_DEFINITION, "not set"))
));
}

@Test
Expand Down