Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RHDM-2029] Executable model doesn't report an error when duplicated #59

Merged
merged 7 commits into from
Jun 20, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ public KnowledgeBuilder buildKnowledgePackages( KieBaseModelImpl kBaseModel, Bui
}
if (compileIncludedKieBases()) {
addFiles( buildFilter, assets, getKieBaseModel( include ), includeModule, useFolders );
} else {
buildContext.addIncludeModule(getKieBaseModel(include), includeModule);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@

package org.drools.compiler.kie.builder.impl;

import java.util.Collections;
import java.util.Map;

import org.kie.api.builder.model.KieBaseModel;

public class BuildContext {
private final ResultsImpl messages;

Expand All @@ -33,4 +38,12 @@ public ResultsImpl getMessages() {
public boolean registerResourceToBuild(String kBaseName, String resource) {
return true;
}

public void addIncludeModule(KieBaseModel kieBaseModel, InternalKieModule includeModule) {
// no op
}

public Map<KieBaseModel, InternalKieModule> getIncludeModules() {
return Collections.emptyMap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ private Collection<String> getRuleClassNames() {
return ruleClassesNames;
}

private Collection<Model> getModelForKBase(KieBaseModelImpl kBaseModel) {
public Collection<Model> getModelForKBase(KieBaseModelImpl kBaseModel) {
Map<String, Model> modelsMap = getModels();
if (kBaseModel.getPackages().isEmpty()) {
return modelsMap.values();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import java.util.Set;

import org.drools.compiler.kie.builder.impl.BuildContext;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kie.builder.impl.ResultsImpl;
import org.kie.api.builder.model.KieBaseModel;

public class CanonicalModelBuildContext extends BuildContext {

Expand All @@ -33,6 +35,8 @@ public class CanonicalModelBuildContext extends BuildContext {
private final Collection<GeneratedClassWithPackage> allGeneratedPojos = new HashSet<>();
private final Map<String, Class<?>> allCompiledClasses = new HashMap<>();

private final Map<KieBaseModel, InternalKieModule> includeModules = new HashMap<>();

public CanonicalModelBuildContext() { }

public CanonicalModelBuildContext(ResultsImpl messages) {
Expand Down Expand Up @@ -81,4 +85,14 @@ private String resource2Package(String resource) {
int pathEndPos = resource.lastIndexOf('/');
return pathEndPos <= 0 ? "" :resource.substring(0, pathEndPos).replace('/', '.');
}

@Override
public void addIncludeModule(KieBaseModel kieBaseModel, InternalKieModule includeModule) {
includeModules.put(kieBaseModel, includeModule);
}

@Override
public Map<KieBaseModel, InternalKieModule> getIncludeModules() {
return includeModules;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,39 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.drools.compiler.builder.impl.KnowledgeBuilderConfigurationImpl;
import org.drools.compiler.builder.impl.KnowledgeBuilderImpl;
import org.drools.compiler.builder.impl.TypeDeclarationFactory;
import org.drools.compiler.compiler.PackageRegistry;
import org.drools.compiler.compiler.ParserError;
import org.drools.compiler.kie.builder.impl.BuildContext;
import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kproject.models.KieBaseModelImpl;
import org.drools.compiler.lang.descr.AbstractClassTypeDeclarationDescr;
import org.drools.compiler.lang.descr.CompositePackageDescr;
import org.drools.compiler.lang.descr.EnumDeclarationDescr;
import org.drools.compiler.lang.descr.GlobalDescr;
import org.drools.compiler.lang.descr.ImportDescr;
import org.drools.compiler.lang.descr.PackageDescr;
import org.drools.compiler.lang.descr.RuleDescr;
import org.drools.compiler.lang.descr.TypeDeclarationDescr;
import org.drools.core.addon.TypeResolver;
import org.drools.core.definitions.InternalKnowledgePackage;
import org.drools.core.rule.ImportDeclaration;
import org.drools.core.rule.TypeDeclaration;
import org.drools.core.util.StringUtils;
import org.drools.model.Model;
import org.drools.modelcompiler.CanonicalKieModule;
import org.drools.modelcompiler.builder.errors.UnsupportedFeatureError;
import org.drools.modelcompiler.builder.generator.DRLIdGenerator;
import org.drools.modelcompiler.builder.generator.DrlxParseUtil;
import org.drools.modelcompiler.builder.generator.declaredtype.POJOGenerator;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.internal.builder.ResultSeverity;

import static com.github.javaparser.StaticJavaParser.parseImport;
Expand All @@ -68,6 +76,8 @@ public class ModelBuilderImpl<T extends PackageSources> extends KnowledgeBuilder

private Map<String, CompositePackageDescr> compositePackagesMap;

private Map<String, Set<String>> includedRuleNameMap = new HashMap<>();

public ModelBuilderImpl(Function<PackageModel, T> sourcesGenerator, KnowledgeBuilderConfigurationImpl configuration, ReleaseId releaseId, boolean oneClassPerRule) {
super(configuration);
this.sourcesGenerator = sourcesGenerator;
Expand Down Expand Up @@ -216,6 +226,8 @@ protected void buildRules(Collection<CompositePackageDescr> packages) {
return;
}

populateIncludedRuleNameMap();

for (CompositePackageDescr packageDescr : packages) {
setAssetFilter(packageDescr.getFilter());
PackageRegistry pkgRegistry = getPackageRegistry(packageDescr.getNamespace());
Expand All @@ -230,6 +242,22 @@ protected void buildRules(Collection<CompositePackageDescr> packages) {
}
}

private void populateIncludedRuleNameMap() {
Map<KieBaseModel, InternalKieModule> includeModules = getBuildContext().getIncludeModules();
for (Map.Entry<KieBaseModel, InternalKieModule> entry : includeModules.entrySet()) {
KieBaseModel kieBaseModel = entry.getKey();
InternalKieModule includeModule = entry.getValue();
if (!(includeModule instanceof CanonicalKieModule)) {
continue;
}
CanonicalKieModule canonicalKieModule = (CanonicalKieModule) includeModule;
Collection<Model> includeModels = canonicalKieModule.getModelForKBase((KieBaseModelImpl)kieBaseModel);
for (Model includeModel : includeModels) {
includeModel.getRules().forEach(rule -> includedRuleNameMap.computeIfAbsent(includeModel.getPackageName(), k -> new HashSet<>()).add(rule.getName()));
}
Comment on lines +253 to +257
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using getModelForKBase instead of getKiePackage. Hopefully, less overhead.

}
}

private void buildDeclaredTypes( Collection<CompositePackageDescr> packages ) {
for (CompositePackageDescr packageDescr : packages) {
PackageRegistry pkgRegistry = getPackageRegistry(packageDescr.getNamespace());
Expand Down Expand Up @@ -303,4 +331,25 @@ public T getPackageSource(String packageName) {
protected BuildContext createBuildContext() {
return new CanonicalModelBuildContext();
}

// Overridden, because exec-model doesn't add assets of included kbase to the packageDescr
@Override
protected void validateUniqueRuleNames(final PackageDescr packageDescr) {
super.validateUniqueRuleNames(packageDescr);

// check for duplicated rule names in included kbase
if (includedRuleNameMap.containsKey(packageDescr.getNamespace())) {
Set<String> ruleNames = includedRuleNameMap.get(packageDescr.getNamespace());
for (final RuleDescr ruleDescr : packageDescr.getRules()) {
if (ruleNames.contains(ruleDescr.getName())) {
addBuilderResult(new ParserError(ruleDescr.getResource(),
"Duplicate rule name: " + ruleDescr.getName(),
ruleDescr.getLine(),
ruleDescr.getColumn(),
packageDescr.getNamespace()));
}
}
}

}
}
2 changes: 1 addition & 1 deletion drools-test-coverage/test-compiler-integration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package org.drools.mvel.integrationtests;

import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.drools.testcoverage.common.util.KieBaseTestConfiguration;
import org.drools.testcoverage.common.util.KieUtil;
Expand All @@ -26,7 +28,9 @@
import org.junit.runners.Parameterized;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.ReleaseId;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Rule;
Expand Down Expand Up @@ -241,4 +245,80 @@ private static long getNumberOfRules(KieBase kieBase) {
}
return nrOfRules;
}

/**
* Test the inclusion of a KieBase defined in one KJAR into the KieBase of another KJAR.
* <p/>
* The 2 KieBases use the duplicate rule names, so an error should be reported
*/
@Test
public void kieBaseIncludesCrossKJarDuplicateRuleNames_shouldReportError() throws IOException {

String pomContentMain = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
"<modelVersion>4.0.0</modelVersion>\n" +
"<groupId>org.kie</groupId>\n" +
"<artifactId>rules-main</artifactId>\n" +
"<version>1.0.0</version>\n" +
"<packaging>jar</packaging>\n" +
"<dependencies>\n" +
"<dependency>\n" +
"<groupId>org.kie</groupId>\n" +
"<artifactId>rules-sub</artifactId>\n" +
"<version>1.0.0</version>\n" +
"</dependency>\n" +
"</dependencies>\n" +
"</project>\n";

String kmoduleContentMain = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<kmodule xmlns=\"http://jboss.org/kie/6.0.0/kmodule\">\n" +
"<kbase name=\"kbaseMain\" equalsBehavior=\"equality\" default=\"true\" packages=\"rules\" includes=\"kbaseSub\">\n" +
"<ksession name=\"ksessionMain\" default=\"true\" type=\"stateful\"/>\n" +
"</kbase>\n" +
"</kmodule>";

String drlMain = "package rules\n" +
"\n" +
"rule \"RuleA\"\n" +
"when\n" +
"then\n" +
"System.out.println(\"Rule in KieBaseMain\");\n" +
"end";

String kmoduleContentSub = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<kmodule xmlns=\"http://jboss.org/kie/6.0.0/kmodule\">\n" +
"<kbase name=\"kbaseSub\" equalsBehavior=\"equality\" default=\"false\" packages=\"rules\">\n" +
"<ksession name=\"ksessionSub\" default=\"false\" type=\"stateful\"/>\n" +
"</kbase>\n" +
"</kmodule>";

String drlSub = "package rules\n" +
"\n" +
"rule \"RuleA\"\n" +
"when\n" +
"then\n" +
"System.out.println(\"Rule in KieBaseSub\");\n" +
"end";

KieServices ks = KieServices.Factory.get();
ReleaseId releaseIdSub = ks.newReleaseId("org.kie", "rules-sub", "1.0.0");

//First deploy the second KJAR on which the first one depends.
KieFileSystem kfsSub = ks.newKieFileSystem()
.generateAndWritePomXML(releaseIdSub)
.write("src/main/resources/rules/rules.drl", drlSub)
.writeKModuleXML(kmoduleContentSub);

KieUtil.getKieBuilderFromKieFileSystem(kieBaseTestConfiguration, kfsSub, true);

KieFileSystem kfsMain = ks.newKieFileSystem()
.writePomXML(pomContentMain)
.write("src/main/resources/rules/rules.drl", drlMain)
.writeKModuleXML(kmoduleContentMain);

KieBuilder kieBuilderMain = KieUtil.getKieBuilderFromKieFileSystem(kieBaseTestConfiguration, kfsMain, false);
List<Message> messages = kieBuilderMain.getResults().getMessages(Message.Level.ERROR);

assertThat(messages).as("Duplication error should be reported")
.extracting(Message::getText).anyMatch(text -> text.contains("Duplicate rule name"));
}
}
Loading