This is an automated email from the ASF dual-hosted git repository.
mariofusco pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/main by this push:
new e04f4bed64 This enables validation that all fact types used in rules
have proper (#6524)
e04f4bed64 is described below
commit e04f4bed645721129a330e2bbd43ed0a21ac681f
Author: Toni Rikkola <[email protected]>
AuthorDate: Thu Nov 27 16:14:26 2025 +0200
This enables validation that all fact types used in rules have proper
(#6524)
declare statements and that field references match declared fields.
Co-authored-by: Claude <[email protected]>
---
.../verifier/builder/ScopesAgendaFilter.java | 2 +
.../org/drools/verifier/components/Definition.java | 123 +++++++++++++++
.../verifier/components/LiteralRestriction.java | 12 +-
.../verifier/components/VerifierComponentType.java | 1 +
.../visitor/ExprConstraintDescrVisitor.java | 1 +
.../visitor/FieldConstraintDescrVisitor.java | 1 +
.../verifier/visitor/PackageDescrVisitor.java | 2 +-
.../visitor/TypeDeclarationDescrVisitor.java | 10 +-
.../definition/DefinitionValidationTest.java | 166 +++++++++++++++++++++
.../definition/DefinitionValidationTest.drl | 59 ++++++++
.../definition/DefinitionVerificationRules.drl | 152 +++++++++++++++++++
.../verifier/definition/MissingDefinitionTest.drl | 46 ++++++
.../definition/UndefinedFieldUsageTest.drl | 51 +++++++
13 files changed, 623 insertions(+), 3 deletions(-)
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/builder/ScopesAgendaFilter.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/builder/ScopesAgendaFilter.java
index f3e28c31dd..96aa2672e7 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/builder/ScopesAgendaFilter.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/builder/ScopesAgendaFilter.java
@@ -32,6 +32,7 @@ public class ScopesAgendaFilter
public final static String VERIFYING_SCOPE_SINGLE_RULE =
"single-rule";
public final static String VERIFYING_SCOPE_DECISION_TABLE =
"decision-table";
public final static String VERIFYING_SCOPE_KNOWLEDGE_PACKAGE =
"knowledge-package";
+ public final static String VERIFYING_SCOPE_DEFINITION_CHECK =
"definition-check";
public final static Collection<String> ALL_SCOPES =
new ArrayList<String>() {
@@ -41,6 +42,7 @@ public class ScopesAgendaFilter
add( VERIFYING_SCOPE_DECISION_TABLE );
add( VERIFYING_SCOPE_SINGLE_RULE );
add( VERIFYING_SCOPE_KNOWLEDGE_PACKAGE );
+
add( VERIFYING_SCOPE_DEFINITION_CHECK );
}
};
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/Definition.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/Definition.java
new file mode 100644
index 0000000000..3335b957ad
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/Definition.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.drools.verifier.components;
+
+import org.drools.drl.ast.descr.TypeDeclarationDescr;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class Definition extends PackageComponent<TypeDeclarationDescr> {
+
+ private String typeName;
+ private String superTypeName;
+ private Map<String, Object> metadata = new HashMap<>();
+ private Map<String, String> declaredFields = new HashMap<>();
+
+ public Definition(TypeDeclarationDescr descr, RulePackage rulePackage) {
+ super(descr, rulePackage);
+ this.typeName = descr.getTypeName();
+ this.superTypeName = descr.getSuperTypeName();
+ initializeDeclaredFields(descr);
+ }
+
+ protected Definition(TypeDeclarationDescr descr, String packageName) {
+ super(descr, packageName);
+ this.typeName = descr.getTypeName();
+ this.superTypeName = descr.getSuperTypeName();
+ initializeDeclaredFields(descr);
+ }
+
+ private void initializeDeclaredFields(TypeDeclarationDescr descr) {
+ if (descr.getFields() != null) {
+ for (String fieldName : descr.getFields().keySet()) {
+ String fieldType =
descr.getFields().get(fieldName).getPattern().getObjectType();
+ this.declaredFields.put(fieldName, fieldType);
+ }
+ }
+ }
+
+ @Override
+ public String getPath() {
+ return String.format("%s/definition[@name='%s']",
+ getPackagePath(),
+ getTypeName());
+ }
+
+ @Override
+ public VerifierComponentType getVerifierComponentType() {
+ return VerifierComponentType.DEFINITION;
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName) {
+ this.typeName = typeName;
+ }
+
+ public String getSuperTypeName() {
+ return superTypeName;
+ }
+
+ public void setSuperTypeName(String superTypeName) {
+ this.superTypeName = superTypeName;
+ }
+
+ public Map<String, Object> getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map<String, Object> metadata) {
+ this.metadata = metadata;
+ }
+
+ public Map<String, String> getDeclaredFields() {
+ return declaredFields;
+ }
+
+ public void setDeclaredFields(Map<String, String> declaredFields) {
+ this.declaredFields = declaredFields;
+ }
+
+ public boolean hasField(String fieldName) {
+ return declaredFields.containsKey(fieldName);
+ }
+
+ public String getFieldType(String fieldName) {
+ return declaredFields.get(fieldName);
+ }
+
+ public Set<String> getFieldNames() {
+ return declaredFields.keySet();
+ }
+
+ @Override
+ public String toString() {
+ return "Definition{" +
+ "typeName='" + typeName + '\'' +
+ ", packageName='" + getPackageName() + '\'' +
+ ", superTypeName='" + superTypeName + '\'' +
+ ", declaredFields=" + declaredFields +
+ '}';
+ }
+}
\ No newline at end of file
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/LiteralRestriction.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/LiteralRestriction.java
index 0eb0c49db8..1ecfe96fb8 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/LiteralRestriction.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/LiteralRestriction.java
@@ -29,12 +29,14 @@ public abstract class LiteralRestriction extends Restriction
implements
Cause {
+ private String fieldName;
+
public LiteralRestriction(Pattern pattern) {
super( pattern );
}
public RestrictionType getRestrictionType() {
- return Restriction.RestrictionType.LITERAL;
+ return RestrictionType.LITERAL;
}
public abstract String getValueAsString();
@@ -96,4 +98,12 @@ public abstract class LiteralRestriction extends Restriction
public String toString() {
return "LiteralRestriction from rule [" + getRuleName() + "] value '"
+ operator.getOperatorString() + " " + getValueAsString() + "'";
}
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
}
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/VerifierComponentType.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/VerifierComponentType.java
index 7949fb3dfb..ea0740bcf6 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/VerifierComponentType.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/components/VerifierComponentType.java
@@ -49,6 +49,7 @@ public class VerifierComponentType
public static final VerifierComponentType ENTRY_POINT_DESCR = new
VerifierComponentType("entryPointDescr");
public static final VerifierComponentType WORKING_MEMORY = new
VerifierComponentType("workingMemory");
public static final VerifierComponentType IMPORT = new
VerifierComponentType("import");
+ public static final VerifierComponentType DEFINITION = new
VerifierComponentType("definition");
public static final VerifierComponentType FIELD_LEVEL_VARIABLE = new
VerifierComponentType("fieldLevelVariable");
private final String type;
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/ExprConstraintDescrVisitor.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/ExprConstraintDescrVisitor.java
index 4c2b1d1d07..afbb01407e 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/ExprConstraintDescrVisitor.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/ExprConstraintDescrVisitor.java
@@ -88,6 +88,7 @@ public class ExprConstraintDescrVisitor {
private void createRestriction(int currentOrderNumber, String value,
Operator operator) {
LiteralRestriction restriction =
LiteralRestriction.createRestriction(pattern, value);
restriction.setFieldPath(field.getPath());
+ restriction.setFieldName(field.getName());
restriction.setPatternIsNot(pattern.isPatternNot());
restriction.setParentPath(pattern.getPath());
restriction.setParentType(pattern.getVerifierComponentType());
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/FieldConstraintDescrVisitor.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/FieldConstraintDescrVisitor.java
index 7f24d185be..4950e78f77 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/FieldConstraintDescrVisitor.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/FieldConstraintDescrVisitor.java
@@ -138,6 +138,7 @@ public class FieldConstraintDescrVisitor {
restriction.setPatternIsNot(pattern.isPatternNot());
restriction.setFieldPath(field.getPath());
+ restriction.setFieldName(field.getName());
restriction.setOperator(Operator.determineOperator(descr.getEvaluator(),
descr.isNegated()));
restriction.setOrderNumber(orderNumber);
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/PackageDescrVisitor.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/PackageDescrVisitor.java
index eb45173a22..e5b2d6aa12 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/PackageDescrVisitor.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/PackageDescrVisitor.java
@@ -59,7 +59,7 @@ public class PackageDescrVisitor {
visitImports(descr.getImports());
- TypeDeclarationDescrVisitor typeDeclarationDescrVisitor = new
TypeDeclarationDescrVisitor(data);
+ TypeDeclarationDescrVisitor typeDeclarationDescrVisitor = new
TypeDeclarationDescrVisitor(data, rulePackage);
typeDeclarationDescrVisitor.visit(descr.getTypeDeclarations());
visitRules(descr.getRules());
diff --git
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/TypeDeclarationDescrVisitor.java
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/TypeDeclarationDescrVisitor.java
index 03b25cadc2..7b1eed453a 100644
---
a/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/TypeDeclarationDescrVisitor.java
+++
b/drools-verifier/drools-verifier-drl/src/main/java/org/drools/verifier/visitor/TypeDeclarationDescrVisitor.java
@@ -20,9 +20,11 @@ package org.drools.verifier.visitor;
import org.drools.drl.ast.descr.AnnotationDescr;
import org.drools.drl.ast.descr.TypeDeclarationDescr;
+import org.drools.verifier.components.Definition;
import org.drools.verifier.components.Field;
import org.drools.verifier.components.Import;
import org.drools.verifier.components.ObjectType;
+import org.drools.verifier.components.RulePackage;
import org.drools.verifier.data.VerifierData;
import java.util.List;
@@ -31,13 +33,18 @@ import java.util.Map;
public class TypeDeclarationDescrVisitor {
private final VerifierData data;
+ private final RulePackage rulePackage;
- public TypeDeclarationDescrVisitor(VerifierData data) {
+ public TypeDeclarationDescrVisitor(VerifierData data, RulePackage
rulePackage) {
this.data = data;
+ this.rulePackage = rulePackage;
}
public void visit(List<TypeDeclarationDescr> typeDeclarationDescrs) {
for (TypeDeclarationDescr typeDeclaration : typeDeclarationDescrs) {
+ // Create Definition component for DRL type definitions
+ Definition definition = new Definition(typeDeclaration,
rulePackage);
+ data.add(definition);
Import objectImport =
data.getImportByName(typeDeclaration.getTypeName());
String objectTypeName;
if (objectImport == null) {
@@ -71,6 +78,7 @@ public class TypeDeclarationDescrVisitor {
Map<String, Object> values =
typeDeclaration.getAnnotation(annDescr.getName()).getValueMap();
for (String value : values.keySet()) {
objectType.getMetadata().put(annDescr.getName(), value);
+ definition.getMetadata().put(annDescr.getName(),
values.get(value));
}
}
}
diff --git
a/drools-verifier/drools-verifier-drl/src/test/java/org/drools/verifier/definition/DefinitionValidationTest.java
b/drools-verifier/drools-verifier-drl/src/test/java/org/drools/verifier/definition/DefinitionValidationTest.java
new file mode 100644
index 0000000000..777a0af3b4
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/test/java/org/drools/verifier/definition/DefinitionValidationTest.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.drools.verifier.definition;
+
+import org.drools.io.ClassPathResource;
+import org.drools.verifier.TestBase;
+import org.drools.verifier.Verifier;
+import org.drools.verifier.VerifierConfiguration;
+import org.drools.verifier.VerifierError;
+import org.drools.verifier.builder.VerifierBuilder;
+import org.drools.verifier.builder.VerifierBuilderFactory;
+import org.drools.verifier.data.VerifierReport;
+import org.drools.verifier.report.components.Severity;
+import org.junit.jupiter.api.Test;
+import org.kie.api.io.ResourceType;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Fail.fail;
+
+public class DefinitionValidationTest extends TestBase {
+
+ @Test
+ void testMissingDefinitionsAndFields() {
+
+ VerifierBuilder vBuilder = VerifierBuilderFactory.newVerifierBuilder();
+
+ VerifierConfiguration vConfiguration =
vBuilder.newVerifierConfiguration();
+
+ // Check that the builder works.
+ assertThat(vBuilder.hasErrors()).isFalse();
+ assertThat(vBuilder.getErrors().size()).isEqualTo(0);
+
+ vConfiguration.getVerifyingResources().put(new
ClassPathResource("DefinitionVerificationRules.drl",
DefinitionValidationTest.class), ResourceType.DRL);
+
+ Verifier verifier = vBuilder.newVerifier(vConfiguration);
+
+ verifier.addResourcesToVerify(new
ClassPathResource("MissingDefinitionTest.drl", DefinitionValidationTest.class),
ResourceType.DRL);
+
+ assertThat(verifier.hasErrors()).isFalse();
+ assertThat(verifier.getErrors().size()).isEqualTo(0);
+
+ boolean works = verifier.fireAnalysis();
+
+ if (!works) {
+ for (VerifierError error : verifier.getErrors()) {
+ System.out.println(error.getMessage());
+ }
+ fail("Could not run verifier");
+ }
+ assertThat(works).isTrue();
+
+ VerifierReport result = verifier.getResult();
+
+
+
result.getBySeverity(Severity.ERROR).stream().forEach(System.out::println);
+
+ assertThat(result).isNotNull();
+ assertThat(result.getBySeverity(Severity.ERROR).size()).isEqualTo(3);
+ assertThat(result.getBySeverity(Severity.WARNING).size()).isEqualTo(0);
+ assertThat(result.getBySeverity(Severity.NOTE).size()).isEqualTo(0);
+
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Missing type definition for fact type:
Employee"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'department' used in rule but not declared in
definition of type 'Employee'"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Missing type definition for fact type:
Vehicle"))).isTrue();
+
+ }
+
+ @Test
+ void testMissingFields() {
+
+ VerifierBuilder vBuilder = VerifierBuilderFactory.newVerifierBuilder();
+
+ VerifierConfiguration vConfiguration =
vBuilder.newVerifierConfiguration();
+
+ // Check that the builder works.
+ assertThat(vBuilder.hasErrors()).isFalse();
+ assertThat(vBuilder.getErrors().size()).isEqualTo(0);
+
+ vConfiguration.getVerifyingResources().put(new
ClassPathResource("DefinitionVerificationRules.drl",
DefinitionValidationTest.class), ResourceType.DRL);
+
+ Verifier verifier = vBuilder.newVerifier(vConfiguration);
+
+ verifier.addResourcesToVerify(new
ClassPathResource("UndefinedFieldUsageTest.drl",
DefinitionValidationTest.class), ResourceType.DRL);
+
+ assertThat(verifier.hasErrors()).isFalse();
+ assertThat(verifier.getErrors().size()).isEqualTo(0);
+
+ boolean works = verifier.fireAnalysis();
+
+ if (!works) {
+ for (VerifierError error : verifier.getErrors()) {
+ System.out.println(error.getMessage());
+ }
+ fail("Could not run verifier");
+ }
+ assertThat(works).isTrue();
+
+ VerifierReport result = verifier.getResult();
+
+ assertThat(result).isNotNull();
+ assertThat(result.getBySeverity(Severity.ERROR).size()).isEqualTo(5);
+ assertThat(result.getBySeverity(Severity.WARNING).size()).isEqualTo(0);
+ assertThat(result.getBySeverity(Severity.NOTE).size()).isEqualTo(0);
+
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'department' used in rule but not declared in
definition of type 'Person'"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'experience' used in rule but not declared in
definition of type 'Person'"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'salary' used in rule but not declared in
definition of type 'Person'"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'year' used in rule but not declared in
definition of type 'Vehicle'"))).isTrue();
+ assertThat(result.getBySeverity(Severity.ERROR).stream().anyMatch(m ->
m.getMessage().contains("Field 'owner' used in rule but not declared in
definition of type 'Vehicle'"))).isTrue();
+
+ }
+
+ @Test
+ void testValidFileWithNestedFacts() {
+
+ VerifierBuilder vBuilder = VerifierBuilderFactory.newVerifierBuilder();
+
+ VerifierConfiguration vConfiguration =
vBuilder.newVerifierConfiguration();
+
+ // Check that the builder works.
+ assertThat(vBuilder.hasErrors()).isFalse();
+ assertThat(vBuilder.getErrors().size()).isEqualTo(0);
+
+ vConfiguration.getVerifyingResources().put(new
ClassPathResource("DefinitionVerificationRules.drl",
DefinitionValidationTest.class), ResourceType.DRL);
+
+ Verifier verifier = vBuilder.newVerifier(vConfiguration);
+
+ verifier.addResourcesToVerify(new
ClassPathResource("DefinitionValidationTest.drl",
DefinitionValidationTest.class), ResourceType.DRL);
+
+ assertThat(verifier.hasErrors()).isFalse();
+ assertThat(verifier.getErrors().size()).isEqualTo(0);
+
+ boolean works = verifier.fireAnalysis();
+
+ if (!works) {
+ for (VerifierError error : verifier.getErrors()) {
+ System.out.println(error.getMessage());
+ }
+ fail("Could not run verifier");
+ }
+ assertThat(works).isTrue();
+
+ VerifierReport result = verifier.getResult();
+
+ assertThat(result).isNotNull();
+ assertThat(result.getBySeverity(Severity.ERROR).size()).isEqualTo(0);
+ assertThat(result.getBySeverity(Severity.WARNING).size()).isEqualTo(0);
+ assertThat(result.getBySeverity(Severity.NOTE).size()).isEqualTo(0);
+ }
+}
diff --git
a/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionValidationTest.drl
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionValidationTest.drl
new file mode 100644
index 0000000000..d0a805b505
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionValidationTest.drl
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.drools.verifier.definition
+
+declare Person
+ name : String
+ age : Integer
+ address : Address
+end
+
+declare Address
+ street : String
+ city : String
+ zipCode : String
+end
+
+declare Vehicle
+ make : String
+ model : String
+ owner : Person
+end
+
+rule "Adult persons"
+when
+ $p : Person( age >= 18 )
+then
+ System.out.println("Adult: " + $p.getName());
+end
+
+rule "City residents"
+when
+ $p : Person( address.city == "New York" )
+then
+ System.out.println("NYC resident: " + $p.getName());
+end
+
+rule "Vehicle owners"
+when
+ $v : Vehicle( owner.age > 21 )
+then
+ System.out.println("Vehicle owned by adult: " + $v.getOwner().getName());
+end
\ No newline at end of file
diff --git
a/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionVerificationRules.drl
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionVerificationRules.drl
new file mode 100644
index 0000000000..76c531f790
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/DefinitionVerificationRules.drl
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+//Verification rules for checking DRL type definitions
+package org.drools.verifier.definition
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.drools.verifier.components.Definition;
+import org.drools.verifier.components.ObjectType;
+import org.drools.verifier.components.LiteralRestriction;
+import org.drools.verifier.components.Pattern;
+import org.drools.verifier.report.components.Severity;
+import org.drools.verifier.report.components.VerifierMessage;
+import org.drools.verifier.report.components.MessageType;
+
+import org.drools.verifier.data.VerifierReport
+import org.drools.verifier.components.Field;
+
+global VerifierReport result;
+
+rule "Missing Definition for ObjectType"
+ when
+ $objectType : ObjectType( $typeName : name )
+ not Definition( typeName == $typeName )
+ then
+ result.add(new VerifierMessage(
+ new HashMap(),
+ Severity.ERROR,
+ MessageType.MISSING_COMPONENT,
+ $objectType,
+ "Missing type definition for fact type: " + $typeName
+ ,
+ new ArrayList() ) );
+end
+
+
+declare FinalField
+ patternName: String
+ fieldName: String
+end
+
+declare Split
+ patternName: String
+ fieldName: String
+ leftOver: String[]
+end
+
+rule "Split"
+ when
+ LiteralRestriction( fieldPath != null, $fieldName : fieldName,
$patternName : patternName )
+ then
+ if($fieldName.contains(".")) {
+ Split split = new Split();
+
+ String[] array = $fieldName.split("\\.");
+ split.setFieldName(array[0]);
+ split.setPatternName( $patternName );
+ split.setLeftOver( java.util.Arrays.copyOfRange(array, 1,
array.length) );
+ insert( split );
+ } else {
+ FinalField ff = new FinalField();
+ ff.setPatternName( $patternName );
+ ff.setFieldName( $fieldName );
+ insert( ff );
+ }
+end
+
+rule "Trim split"
+ when
+ $split :Split( $fieldName :fieldName, eval( leftOver.length > 0) )
+ $definition : Definition( typeName == $split.patternName, fieldNames
contains $fieldName)
+ then
+ String fieldType = $definition.getDeclaredFields().get($fieldName);
+ String[] oldArray = $split.getLeftOver();
+ String[] newArray = java.util.Arrays.copyOfRange(oldArray, 1,
oldArray.length);
+ $split.setFieldName(oldArray[0]);
+ $split.setPatternName( fieldType );
+ $split.setLeftOver( newArray );
+ update( $split );
+
+end
+
+rule "Add final field"
+ when
+ Split( $patternName : patternName, $fieldName : fieldName, eval(
leftOver.length == 0))
+ then
+ FinalField ff = new FinalField();
+ ff.setPatternName( $patternName );
+ ff.setFieldName( $fieldName );
+ insert( ff );
+end
+
+rule "Missing Field in Definition"
+ when
+ $restriction : FinalField( $fieldName : fieldName )
+ $definition : Definition( typeName == $restriction.patternName,
fieldNames not contains $fieldName )
+ then
+ result.add(new VerifierMessage(
+ new HashMap(),
+ Severity.ERROR,
+ MessageType.MISSING_COMPONENT,
+ $definition,
+ "Field '" + $fieldName + "' used in rule but not
declared in definition of type '" + $restriction.getPatternName() + "'",
+ new ArrayList() ) );
+end
+
+rule "Missing Field in a missing Definition"
+ when
+ $restriction : FinalField( $fieldName : fieldName )
+ not Definition( typeName == $restriction.patternName )
+ then
+ result.add(new VerifierMessage(
+ new HashMap(),
+ Severity.ERROR,
+ MessageType.MISSING_COMPONENT,
+ null,
+ "Field '" + $fieldName + "' used in rule but not
declared in definition of type '" + $restriction.getPatternName() + "'",
+ new ArrayList() ) );
+end
+
+rule "Error when Definition exists, but it is lacking a field"
+ when
+ $split :Split( $fieldName :fieldName, $patternName :patternName)
+ $definition : Definition( typeName == $split.patternName, fieldNames
not contains $split.fieldName)
+ then
+ result.add(new VerifierMessage(
+ new HashMap(),
+ Severity.ERROR,
+ MessageType.MISSING_COMPONENT,
+ null,
+ "Field '" + $fieldName + "' used in rule but
not declared in definition of type '" + $patternName + "'",
+ new ArrayList() ) );
+end
+
diff --git
a/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/MissingDefinitionTest.drl
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/MissingDefinitionTest.drl
new file mode 100644
index 0000000000..f8c87bdfad
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/MissingDefinitionTest.drl
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.drools.verifier.definition
+
+declare Person
+ name : String
+ age : Integer
+end
+
+rule "Adult persons"
+when
+ $p : Person( age >= 18 )
+then
+ System.out.println("Adult: " + $p.getName());
+end
+
+rule "Company employees"
+when
+ $e : Employee( department == "Engineering" )
+then
+ System.out.println("Engineer: " + $e.getName());
+end
+
+rule "Vehicle owners"
+when
+ $v : Vehicle( owner.age > 21 )
+then
+ System.out.println("Vehicle owned by adult: " + $v.getOwner().getName());
+end
\ No newline at end of file
diff --git
a/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/UndefinedFieldUsageTest.drl
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/UndefinedFieldUsageTest.drl
new file mode 100644
index 0000000000..35b24494fc
--- /dev/null
+++
b/drools-verifier/drools-verifier-drl/src/test/resources/org/drools/verifier/definition/UndefinedFieldUsageTest.drl
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.drools.verifier.definition
+
+declare Person
+ name : String
+ age : Integer
+end
+
+declare Vehicle
+ make : String
+ model : String
+end
+
+rule "Person with undefined field"
+when
+ $p : Person( name != null, age > 18, salary > 50000 ) // salary not
defined
+then
+ System.out.println("Person: " + $p.getName());
+end
+
+rule "Vehicle with undefined fields"
+when
+ $v : Vehicle( make == "Toyota", year > 2020, owner.age > 25 ) // year and
owner not defined
+then
+ System.out.println("Vehicle: " + $v.getMake());
+end
+
+rule "Multiple undefined fields"
+when
+ $p : Person( department == "IT", experience > 5 ) // department and
experience not defined
+then
+ System.out.println("Employee: " + $p.getName());
+end
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]