NodeTypeValidator implements DocumentViewXmlValidator, JcrPathValidator { @Override public @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull NodeContext nodeContext, boolean isRoot) { if (node.primary == null) { if (filter.contains(nodeContext.getNodePath()) && !node.props.isEmpty()) { return Collections.singleton( new ValidationMessage(defaultSeverity, String.format(MESSAGE_MISSING_PRIMARY_TYPE, nodeContext.getNodePath()))); } else { return null; } } if (aclManagement.isACLNodeType(node.primary) || userManagement.isAuthorizableNodeType(node.primary)) { protectedNodeContext = nodeContext; } boolean allowProtectedSubNodesAndProperties = protectedNodeContext != null; Collection<ValidationMessage> messages = new LinkedList<>(); String parentNodePath = Text.getRelativeParent(nodeContext.getNodePath(), 1); NodeNameAndType parentNodeNameAndType = nodeTypePerPath.get(parentNodePath); NodeNameAndType newNodeNameAndType = null; try { if (!aclManagement.isACLNodeType(node.primary)) { final EffectiveNodeType parentNodeType; final boolean useDefaultNodeType; if (parentNodeNameAndType == null || !filter.contains(parentNodePath)) { parentNodeType = defaultType; useDefaultNodeType = true; } else if (!parentNodeNameAndType.isUnknown()) { parentNodeType = parentNodeNameAndType.getEffectiveNodeType(); useDefaultNodeType = false; } else { parentNodeType = null; useDefaultNodeType = false; } if (parentNodeType != null) { String constraintViolation = getChildNodeConstraintViolation(node, parentNodeType, ntManagerProvider.getNodeTypeDefinitionProvider(), ntManagerProvider.getNameResolver(), ntManagerProvider.getItemDefinitionProvider(), allowProtectedSubNodesAndProperties); if (constraintViolation != null) { messages.add(new ValidationMessage(defaultSeverity, String.format( useDefaultNodeType ? MESSAGE_CHILD_NODE_OF_NOT_CONTAINED_PARENT_POTENTIALLY_NOT_ALLOWED : MESSAGE_CHILD_NODE_NOT_ALLOWED, getDocViewNodeLabel(node), effectiveNodeTypeToString(ntManagerProvider.getNameResolver(), parentNodeType), constraintViolation))); } } } newNodeNameAndType = new NodeNameAndType(ntManagerProvider.getNameResolver(), ntManagerProvider.getEffectiveNodeTypeProvider(), node); nodeTypePerPath.put(nodeContext.getNodePath(), newNodeNameAndType); Collection<Name> foundProperties = new ArrayList<>(node.props.size()); for (DocViewProperty property : node.props.values()) { String constraintViolation = getPropertyConstraintViolation(property, newNodeNameAndType.getEffectiveNodeType(), allowProtectedSubNodesAndProperties); if (constraintViolation != null) { messages.add(new ValidationMessage(defaultSeverity, String.format(MESSAGE_PROPERTY_NOT_ALLOWED, property, effectiveNodeTypeToString(ntManagerProvider.getNameResolver(), newNodeNameAndType.getEffectiveNodeType()), constraintViolation))); } foundProperties.add(NameFactoryImpl.getInstance().create(property.name)); } for (QPropertyDefinition mandatoryPropertyDefinition : newNodeNameAndType.getEffectiveNodeType() .getMandatoryQPropertyDefinitions()) { if (!mandatoryPropertyDefinition.isAutoCreated() && !foundProperties.contains(mandatoryPropertyDefinition.getName())) { List<Name> ignoredProperties = IGNORED_MANDATORY_PROPERTIES_PER_NODE_TYPE .get(mandatoryPropertyDefinition.getDeclaringNodeType()); if (ignoredProperties != null && ignoredProperties.contains(mandatoryPropertyDefinition.getName())) { continue; } messages.add(new ValidationMessage(defaultSeverity, String.format(MESSAGE_MANDATORY_PROPERTY_MISSING, mandatoryPropertyDefinition.getName(), effectiveNodeTypeToString(ntManagerProvider.getNameResolver(), newNodeNameAndType.getEffectiveNodeType())))); } } } catch (NoSuchNodeTypeException | IllegalNameException | NamespaceException e) { if (!loggedUnknownNodeTypeMessages.contains(e.getMessage())) { messages.add(new ValidationMessage(severityForUnknownNodeTypes, String.format(MESSAGE_UNKNOWN_NODE_TYPE_OR_NAMESPACE, e.getMessage()), e)); loggedUnknownNodeTypeMessages.add(e.getMessage()); } if (newNodeNameAndType == null) { nodeTypePerPath.put(nodeContext.getNodePath(), NodeNameAndType.createUnknownNodeNameAndType(parentNodeNameAndType)); } } catch (RepositoryException e) { throw new IllegalStateException("Could not validate nodes/properties against node types: " + e.getMessage(), e); } return messages; } NodeTypeValidator(@NotNull WorkspaceFilter filter, @NotNull NodeTypeManagerProvider ntManagerProvider,
            @NotNull EffectiveNodeType defaultEffectiveNodeType, @NotNull ValidationMessageSeverity defaultSeverity,
            @NotNull ValidationMessageSeverity severityForUnknownNodeTypes); @Override @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull NodeContext nodeContext,
            boolean isRoot); @Override @Nullable Collection<ValidationMessage> validateEnd(@NotNull DocViewNode node, @NotNull NodeContext nodeContext,
            boolean isRoot); @Override @Nullable Collection<ValidationMessage> validateJcrPath(@NotNull NodeContext nodeContext, boolean isFolder); @Override @Nullable Collection<ValidationMessage> done();  }
@Test @Ignore public void testValidateComplexUnstructuredNodeTypes() throws IOException, RepositoryException, ParseException, ConfigurationException { NodeContext nodeContext = new NodeContextImpl("/apps/test/node4", Paths.get("node4"), Paths.get("")); Map<String, DocViewProperty> props = new HashMap<>(); DocViewProperty property = new DocViewProperty("{}prop1", new String[] { "value1" }, false, PropertyType.STRING); props.put("{}prop1", property); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { "nt:unstructured" }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, props, null, "sling:Folder"); Assert.assertNull(validator.validate(node, nodeContext, false)); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { "value1" }, false, PropertyType.STRING)); node = new DocViewNode("test", "test", null, props, null, "nt:folder"); ValidationExecutorTest.assertViolation(validator.validate(node, nodeContext, false), new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(NodeTypeValidator.MESSAGE_PROPERTY_NOT_ALLOWED, property, "nt:folder", "No property definition found for name!"))); }
@Test public void testInvalidChildNodeTypeBelowDefault() { NodeContext nodeContext = new NodeContextImpl("/apps/test/node4", Paths.get("node4"), Paths.get("")); Map<String, DocViewProperty> props = new HashMap<>(); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { JcrConstants.NT_UNSTRUCTURED }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, props, null, JcrConstants.NT_UNSTRUCTURED); ValidationExecutorTest.assertViolation(validator.validate(node, nodeContext, false), new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(NodeTypeValidator.MESSAGE_CHILD_NODE_OF_NOT_CONTAINED_PARENT_POTENTIALLY_NOT_ALLOWED, "jcr:root [nt:unstructured]", JcrConstants.NT_FOLDER, "Could not find matching child node definition in parent's node type"))); }
@Test public void testNotAllowedProperty() { NodeContext nodeContext = new NodeContextImpl("/apps/test/node4", Paths.get("node4"), Paths.get("")); Map<String, DocViewProperty> props = new HashMap<>(); DocViewProperty prop = new DocViewProperty("{}invalid-prop", new String[] { "some-value" }, false, PropertyType.STRING); props.put("{}invalid-prop", prop); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { JcrConstants.NT_FILE }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, props, null, JcrConstants.NT_FILE); ValidationExecutorTest.assertViolation(validator.validate(node, nodeContext, false), new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(NodeTypeValidator.MESSAGE_PROPERTY_NOT_ALLOWED, prop, JcrConstants.NT_FILE, "No property definition found for name!"))); }
@Test(expected = IllegalStateException.class) public void testPropertyWitInconvertibleValue() { NodeContext nodeContext = new NodeContextImpl("/apps/test/node4", Paths.get("node4"), Paths.get("")); Map<String, DocViewProperty> props = new HashMap<>(); DocViewProperty prop = new DocViewProperty(Property.JCR_CREATED, new String[] { "some-invalid-value" }, true, PropertyType.DATE); props.put(Property.JCR_CREATED, prop); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { JcrConstants.NT_FILE }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, props, null, JcrConstants.NT_FILE); validator.validate(node, nodeContext, false); }
@Test public void testUnknownNamespace() { NodeContext nodeContext = new NodeContextImpl("/apps/test/node4", Paths.get("node4"), Paths.get("")); Map<String, DocViewProperty> props = new HashMap<>(); DocViewProperty prop = new DocViewProperty("{}invalid-prop", new String[] { "some-value" }, false, PropertyType.STRING); props.put("{}invalid-prop", prop); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { "sling:Folder" }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, props, null, "sling:Folder"); ValidationExecutorTest.assertViolation(validator.validate(node, nodeContext, false), new ValidationMessage(ValidationMessageSeverity.WARN, String.format(NodeTypeValidator.MESSAGE_UNKNOWN_NODE_TYPE_OR_NAMESPACE, "Invalid primary type sling:Folder: 'sling: is not a registered namespace prefix.'"))); }
@Test public void testExistenceOfPrimaryNodeTypes() throws IOException, ConfigurationException, RepositoryException, ParseException { validator = createValidator(filter, NodeType.NT_UNSTRUCTURED); Map<String, DocViewProperty> props = new HashMap<>(); props.put("{}prop1", new DocViewProperty("{}prop1", new String[] { "value1" }, false, PropertyType.STRING)); DocViewNode node = new DocViewNode("jcr:root", "jcr:root", null, Collections.emptyMap(), null, null); Assert.assertThat(validator.validate(node, new NodeContextImpl("/apps/test", Paths.get("/some/path"), Paths.get("")), false), AnyValidationMessageMatcher.noValidationInCollection()); node = new DocViewNode("jcr:root", "jcr:root", null, props, null, null); Assert.assertThat( validator.validate(node, new NodeContextImpl("/apps/test2/invalid", Paths.get("/some/path"), Paths.get("")), false), AnyValidationMessageMatcher.noValidationInCollection()); ValidationExecutorTest.assertViolation( validator.validate(node, new NodeContextImpl("/apps/test", Paths.get("/some/path"), Paths.get("")), false), new ValidationMessage(ValidationMessageSeverity.ERROR, String.format(NodeTypeValidator.MESSAGE_MISSING_PRIMARY_TYPE, "/apps/test"))); props.put(NameConstants.JCR_PRIMARYTYPE.toString(), new DocViewProperty(NameConstants.JCR_PRIMARYTYPE.toString(), new String[] { "nt:unstructured" }, false, PropertyType.STRING)); node = new DocViewNode("jcr:root", "jcr:root", null, props, null, "nt:unstructured"); Assert.assertThat(validator.validate(node, new NodeContextImpl("/apps/test", Paths.get("/some/path"), Paths.get("")), false), AnyValidationMessageMatcher.noValidationInCollection()); }