From 6aef805c629c8f6a815dfec732810755e596595c Mon Sep 17 00:00:00 2001 From: Edoardo Vacchi Date: Wed, 27 Mar 2019 13:56:08 +0100 Subject: [PATCH] rebased --- .../org/kie/submarine/rules/DataSource.java | 26 +++ .../org/kie/submarine/rules/RuleUnit.java | 5 + .../kie/submarine/rules/RuleUnitInstance.java | 6 + .../java/org/kie/submarine/rules/Unit.java | 5 + .../rules/impl/AbstractRuleUnit.java | 7 + .../rules/impl/AbstractRuleUnitInstance.java | 50 +++++ .../submarine/rules/impl/ListDataSource.java | 41 ++++ .../builder/CanonicalModelKieProject.java | 147 ++++---------- .../builder/ModelSourceClass.java | 74 +++++++ .../modelcompiler/builder/ModelWriter.java | 1 + .../modelcompiler/builder/PackageModel.java | 11 ++ .../builder/ProjectSourceClass.java | 48 +++++ .../builder/generator/ModelGenerator.java | 28 ++- .../builder/generator/ModuleSourceClass.java | 81 ++++++++ .../RuleUnitInstanceSourceClass.java | 72 +++++++ .../generator/RuleUnitSourceClass.java | 131 ++++++++++++ kie-maven-plugin/pom.xml | 28 ++- .../maven/plugin/CanonicalModelWriter.java | 66 +++++++ .../kie/maven/plugin/GenerateModelMojo.java | 187 ++++++++---------- .../kie/maven/plugin/ResourceFileWriter.java | 40 ++++ 20 files changed, 831 insertions(+), 223 deletions(-) create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/DataSource.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnit.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnitInstance.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/Unit.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnit.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnitInstance.java create mode 100644 api/kie-api/src/main/java/org/kie/submarine/rules/impl/ListDataSource.java create mode 100644 drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelSourceClass.java create mode 100644 drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ProjectSourceClass.java create mode 100644 drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModuleSourceClass.java create mode 100644 drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitInstanceSourceClass.java create mode 100644 drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitSourceClass.java create mode 100644 kie-maven-plugin/src/main/java/org/kie/maven/plugin/CanonicalModelWriter.java create mode 100644 kie-maven-plugin/src/main/java/org/kie/maven/plugin/ResourceFileWriter.java diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/DataSource.java b/api/kie-api/src/main/java/org/kie/submarine/rules/DataSource.java new file mode 100644 index 00000000000..c66763f14d9 --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/DataSource.java @@ -0,0 +1,26 @@ +package org.kie.submarine.rules; + +import org.kie.api.runtime.rule.FactHandle; + +public interface DataSource { + + FactHandle add(T object ); + + /** + * Updates the fact for which the given FactHandle was assigned with the new + * fact set as the second parameter in this method. + * It is also possible to optionally specify the set of properties that have been modified. + * + * @param handle the FactHandle for the fact to be updated. + * @param object the new value for the fact being updated. + */ + void update(FactHandle handle, T object); + + /** + * Deletes the fact for which the given FactHandle was assigned + * + * @param handle the handle whose fact is to be retracted. + */ + void remove(FactHandle handle); + +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnit.java b/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnit.java new file mode 100644 index 00000000000..96142f33f7e --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnit.java @@ -0,0 +1,5 @@ +package org.kie.submarine.rules; + +public interface RuleUnit { + RuleUnitInstance createInstance(T workingMemory); +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnitInstance.java b/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnitInstance.java new file mode 100644 index 00000000000..f7a6039deae --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/RuleUnitInstance.java @@ -0,0 +1,6 @@ +package org.kie.submarine.rules; + +public interface RuleUnitInstance { + RuleUnit unit(); + void fire(); +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/Unit.java b/api/kie-api/src/main/java/org/kie/submarine/rules/Unit.java new file mode 100644 index 00000000000..20e7739d1eb --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/Unit.java @@ -0,0 +1,5 @@ +package org.kie.submarine.rules; + +public @interface Unit { + +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnit.java b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnit.java new file mode 100644 index 00000000000..18ed04b9e28 --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnit.java @@ -0,0 +1,7 @@ +package org.kie.submarine.rules.impl; + +import org.kie.submarine.rules.RuleUnit; + +public abstract class AbstractRuleUnit implements RuleUnit { + +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnitInstance.java b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnitInstance.java new file mode 100644 index 00000000000..00e52c33bc8 --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/AbstractRuleUnitInstance.java @@ -0,0 +1,50 @@ +package org.kie.submarine.rules.impl; + +import java.lang.reflect.Field; + +import org.kie.api.runtime.KieSession; +import org.kie.submarine.rules.RuleUnit; +import org.kie.submarine.rules.RuleUnitInstance; + +public class AbstractRuleUnitInstance implements RuleUnitInstance { + + private final T workingMemory; + private final RuleUnit unit; + private final KieSession rt; + + public AbstractRuleUnitInstance(RuleUnit unit, T workingMemory, KieSession rt) { + this.unit = unit; + this.rt = rt; + this.workingMemory = workingMemory; + } + + public void fire() { + magicReflectionThingie(rt, workingMemory); + rt.fireAllRules(); + } + + @Override + public RuleUnit unit() { + return unit; + } + + public T workingMemory() { + return workingMemory; + } + + private void magicReflectionThingie(KieSession rt, T workingMemory) { + try { + for (Field f : workingMemory.getClass().getDeclaredFields()) { + f.setAccessible(true); + Object v = null; + v = f.get(workingMemory); + if (v instanceof ListDataSource) { + ListDataSource o = (ListDataSource) v; + o.drainInto(rt::insert); + } + } + } catch (IllegalAccessException e) { + throw new Error(e); + } + } +} diff --git a/api/kie-api/src/main/java/org/kie/submarine/rules/impl/ListDataSource.java b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/ListDataSource.java new file mode 100644 index 00000000000..53089b0c054 --- /dev/null +++ b/api/kie-api/src/main/java/org/kie/submarine/rules/impl/ListDataSource.java @@ -0,0 +1,41 @@ +package org.kie.submarine.rules.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.function.Consumer; + +import org.kie.api.runtime.rule.FactHandle; +import org.kie.submarine.rules.DataSource; + +public class ListDataSource implements DataSource { + ArrayList values = new ArrayList<>(); + + public FactHandle add(T t) { + values.add(t); + return null; + } + + @Override + public void update(FactHandle handle, T object) { + + } + + @Override + public void remove(FactHandle handle) { + + } + + public void addAll(Collection ts) { + values.addAll(ts); + } + + public void drainInto(Consumer sink) { + Iterator iter = values.iterator(); + while(iter.hasNext()) { + T t = iter.next(); + sink.accept(t); + iter.remove(); + } + } +} diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/CanonicalModelKieProject.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/CanonicalModelKieProject.java index ec0687439ad..c3e681bdd5d 100644 --- a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/CanonicalModelKieProject.java +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/CanonicalModelKieProject.java @@ -29,24 +29,16 @@ import org.drools.compiler.kie.builder.impl.InternalKieModule; import org.drools.compiler.kie.builder.impl.KieModuleKieProject; import org.drools.compiler.kie.builder.impl.ResultsImpl; -import org.drools.compiler.kproject.ReleaseIdImpl; import org.drools.compiler.kproject.models.KieBaseModelImpl; import org.drools.core.util.Drools; -import org.drools.model.Model; import org.drools.modelcompiler.CanonicalKieModule; -import org.kie.api.KieBase; import org.kie.api.builder.Message; -import org.kie.api.builder.ReleaseId; -import org.kie.api.builder.model.KieBaseModel; -import org.kie.api.runtime.KieSession; import org.kie.internal.builder.KnowledgeBuilder; import org.kie.internal.jci.CompilationProblem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.joining; - import static org.drools.modelcompiler.CanonicalKieModule.MODEL_FILE; import static org.drools.modelcompiler.CanonicalKieModule.MODEL_VERSION; import static org.drools.modelcompiler.CanonicalKieModule.createFromClassLoader; @@ -57,12 +49,12 @@ public class CanonicalModelKieProject extends KieModuleKieProject { Logger logger = LoggerFactory.getLogger(CanonicalModelKieProject.class); public static final String PROJECT_RUNTIME_CLASS = "org.drools.project.model.ProjectRuntime"; - public static final String PROJECT_RUNTIME_RESOURCE_CLASS = PROJECT_RUNTIME_CLASS.replace( '.', '/' ) + ".class"; - protected static final String PROJECT_RUNTIME_SOURCE = "src/main/java/" + PROJECT_RUNTIME_CLASS.replace( '.', '/' ) + ".java"; + public static final String PROJECT_RUNTIME_RESOURCE_CLASS = PROJECT_RUNTIME_CLASS.replace('.', '/') + ".class"; + protected static final String PROJECT_RUNTIME_SOURCE = "src/main/java/" + PROJECT_RUNTIME_CLASS.replace('.', '/') + ".java"; public static final String PROJECT_MODEL_CLASS = "org.drools.project.model.ProjectModel"; - public static final String PROJECT_MODEL_RESOURCE_CLASS = PROJECT_MODEL_CLASS.replace( '.', '/' ) + ".class"; - protected static final String PROJECT_MODEL_SOURCE = "src/main/java/" + PROJECT_MODEL_CLASS.replace( '.', '/' ) + ".java"; + public static final String PROJECT_MODEL_RESOURCE_CLASS = PROJECT_MODEL_CLASS.replace('.', '/') + ".class"; + protected static final String PROJECT_MODEL_SOURCE = "src/main/java/" + PROJECT_MODEL_CLASS.replace('.', '/') + ".java"; private final boolean isPattern; @@ -73,13 +65,13 @@ public static BiFunction cr protected List modelBuilders = new ArrayList<>(); public CanonicalModelKieProject(boolean isPattern, InternalKieModule kieModule, ClassLoader classLoader) { - super(kieModule instanceof CanonicalKieModule ? kieModule : createFromClassLoader( classLoader, kieModule ), classLoader); + super(kieModule instanceof CanonicalKieModule ? kieModule : createFromClassLoader(classLoader, kieModule), classLoader); this.isPattern = isPattern; } @Override protected KnowledgeBuilder createKnowledgeBuilder(KieBaseModelImpl kBaseModel, InternalKieModule kModule) { - ModelBuilderImpl modelBuilder = new ModelBuilderImpl(getBuilderConfiguration( kBaseModel, kModule ), isPattern); + ModelBuilderImpl modelBuilder = new ModelBuilderImpl(getBuilderConfiguration(kBaseModel, kModule), isPattern); modelBuilders.add(modelBuilder); return modelBuilder; } @@ -92,131 +84,58 @@ public void writeProjectOutput(MemoryFileSystem trgMfs, ResultsImpl messages) { List sourceFiles = new ArrayList<>(); for (ModelBuilderImpl modelBuilder : modelBuilders) { - final ModelWriter.Result result = modelWriter.writeModel( srcMfs, modelBuilder.getPackageModels() ); + final ModelWriter.Result result = modelWriter.writeModel(srcMfs, modelBuilder.getPackageModels()); modelFiles.addAll(result.getModelFiles()); sourceFiles.addAll(result.getSources()); } KieModuleModelMethod modelMethod = new KieModuleModelMethod(kBaseModels); if (!sourceFiles.isEmpty()) { - String[] sources = sourceFiles.toArray( new String[sourceFiles.size()+2] ); + String[] sources = sourceFiles.toArray(new String[sourceFiles.size() + 2]); + + new ModelSourceClass( + getInternalKieModule().getReleaseId(), + modelMethod, + modelFiles) + .write(srcMfs); - String modelSourceClass = buildModelSourceClass(modelMethod, modelFiles); - logger.debug(modelSourceClass); - srcMfs.write(PROJECT_MODEL_SOURCE, modelSourceClass.getBytes()); - sources[sources.length-2] = PROJECT_MODEL_SOURCE; + sources[sources.length - 2] = PROJECT_MODEL_SOURCE; - String projectSourceClass = buildProjectSourceClass(modelMethod); + String projectSourceClass = new ProjectSourceClass(modelMethod).generate(); logger.debug(projectSourceClass); - srcMfs.write( PROJECT_RUNTIME_SOURCE, projectSourceClass.getBytes()); - sources[sources.length-1] = PROJECT_RUNTIME_SOURCE; + srcMfs.write(PROJECT_RUNTIME_SOURCE, projectSourceClass.getBytes()); + sources[sources.length - 1] = PROJECT_RUNTIME_SOURCE; CompilationResult res = getCompiler().compile(sources, srcMfs, trgMfs, getClassLoader()); - Stream.of(res.getErrors()).collect(groupingBy( CompilationProblem::getFileName)) - .forEach( (name, errors) -> { - errors.forEach( messages::addMessage ); - File srcFile = srcMfs.getFile( name ); - if ( srcFile instanceof MemoryFile ) { - String src = new String ( srcMfs.getFileContents( ( MemoryFile ) srcFile ) ); - messages.addMessage( Message.Level.ERROR, name, "Java source of " + name + " in error:\n" + src); + Stream.of(res.getErrors()).collect(groupingBy(CompilationProblem::getFileName)) + .forEach((name, errors) -> { + errors.forEach(messages::addMessage); + File srcFile = srcMfs.getFile(name); + if (srcFile instanceof MemoryFile) { + String src = new String(srcMfs.getFileContents((MemoryFile) srcFile)); + messages.addMessage(Message.Level.ERROR, name, "Java source of " + name + " in error:\n" + src); } - } ); + }); for (CompilationProblem problem : res.getWarnings()) { messages.addMessage(problem); } } else { - srcMfs.write(PROJECT_MODEL_SOURCE, buildModelSourceClass( modelMethod, modelFiles ).getBytes()); - CompilationResult res = getCompiler().compile(new String[] { PROJECT_MODEL_SOURCE }, srcMfs, trgMfs, getClassLoader()); + new ModelSourceClass(getInternalKieModule().getReleaseId(), modelMethod, modelFiles) + .write(srcMfs); + CompilationResult res = getCompiler().compile(new String[]{PROJECT_MODEL_SOURCE}, srcMfs, trgMfs, getClassLoader()); System.out.println(res.getErrors()); } writeModelFile(modelFiles, trgMfs); } - protected void writeModelFile( List modelSources, MemoryFileSystem trgMfs) { + protected void writeModelFile(List modelSources, MemoryFileSystem trgMfs) { String pkgNames = MODEL_VERSION + Drools.getFullVersion() + "\n"; - if(!modelSources.isEmpty()) { - pkgNames += modelSources.stream().collect( Collectors.joining("\n")); + if (!modelSources.isEmpty()) { + pkgNames += modelSources.stream().collect(Collectors.joining("\n")); } - trgMfs.write( MODEL_FILE, pkgNames.getBytes() ); - } - - protected String buildModelSourceClass( KieModuleModelMethod modelMethod, List modelSources ) { - ReleaseId releaseId = getInternalKieModule().getReleaseId(); - - StringBuilder sb = new StringBuilder(); - sb.append( - "package org.drools.project.model;\n" + - "\n" + - "import " + Model.class.getCanonicalName() + ";\n" + - "import " + ReleaseId.class.getCanonicalName() + ";\n" + - "import " + ReleaseIdImpl.class.getCanonicalName() + ";\n" + - "\n" + - "public class ProjectModel implements org.drools.modelcompiler.CanonicalKieModuleModel {\n" + - "\n"); - sb.append( - " @Override\n" + - " public String getVersion() {\n" + - " return \"" ); - sb.append( Drools.getFullVersion() ); - sb.append( - "\";\n" + - " }\n" + - "\n" + - " @Override\n" + - " public java.util.List getModels() {\n" + - " return java.util.Arrays.asList(" ); - sb.append( modelSources.isEmpty() ? "" : modelSources.stream().collect( joining("(), new ", "new ", "()") ) ); - sb.append( - ");\n" + - " }\n" + - "\n" + - " @Override\n" + - " public ReleaseId getReleaseId() {\n" + - " return new ReleaseIdImpl(\"" ); - sb.append( releaseId.getGroupId() ).append( "\", \"" ); - sb.append( releaseId.getArtifactId() ).append( "\", \"" ); - sb.append( releaseId.getVersion() ).append( "\"" ); - sb.append( - ");\n" + - " }\n"); - sb.append("\n"); - sb.append(modelMethod.toGetKieModuleModelMethod()); - sb.append("\n}" ); - return sb.toString(); - } - - protected String buildProjectSourceClass( KieModuleModelMethod modelMethod ) { - StringBuilder sb = new StringBuilder(); - sb.append( - "package org.drools.project.model;\n" + - "\n" + - "import " + Model.class.getCanonicalName() + ";\n" + - "import " + KieBase.class.getCanonicalName() + ";\n" + - "import " + KieBaseModel.class.getCanonicalName() + ";\n" + - "import " + KieSession.class.getCanonicalName() + ";\n" + - "\n" + - ( hasCdi() ? "@javax.enterprise.context.ApplicationScoped\n" : "" ) + - "public class ProjectRuntime implements org.drools.modelcompiler.KieRuntimeBuilder {\n" + - "\n"); - sb.append(modelMethod.getConstructor()); - sb.append("\n"); - sb.append(modelMethod.toNewKieSessionMethod()); - sb.append("\n"); - sb.append(modelMethod.toGetKieBaseForSessionMethod()); - sb.append("\n"); - sb.append(modelMethod.toKieSessionConfMethod()); - sb.append("\n}" ); - return sb.toString(); - } - - private boolean hasCdi() { - try { - Class.forName( "javax.enterprise.context.ApplicationScoped", false, getClassLoader() ); - return true; - } catch (ClassNotFoundException cnfe) { } - return false; + trgMfs.write(MODEL_FILE, pkgNames.getBytes()); } } \ No newline at end of file diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelSourceClass.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelSourceClass.java new file mode 100644 index 00000000000..3a06989c45b --- /dev/null +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelSourceClass.java @@ -0,0 +1,74 @@ +package org.drools.modelcompiler.builder; + +import java.util.List; + +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.compiler.kproject.ReleaseIdImpl; +import org.drools.core.util.Drools; +import org.drools.model.Model; +import org.kie.api.builder.ReleaseId; + +import static java.util.stream.Collectors.joining; + +public class ModelSourceClass { + + private final List modelSources; + private final KieModuleModelMethod modelMethod; + private final ReleaseId releaseId; + + public ModelSourceClass( + ReleaseId releaseId, + KieModuleModelMethod modelMethod, + List modelSources) { + this.releaseId = releaseId; + this.modelSources = modelSources; + this.modelMethod = modelMethod; + } + + public void write(MemoryFileSystem srcMfs) { + srcMfs.write(CanonicalModelKieProject.PROJECT_MODEL_SOURCE, generate().getBytes()); + } + + public String generate() { + StringBuilder sb = new StringBuilder(); + sb.append( + "package org.drools.project.model;\n" + + "\n" + + "import " + Model.class.getCanonicalName() + ";\n" + + "import " + ReleaseId.class.getCanonicalName() + ";\n" + + "import " + ReleaseIdImpl.class.getCanonicalName() + ";\n" + + "\n" + + "public class ProjectModel implements org.drools.modelcompiler.CanonicalKieModuleModel {\n" + + "\n"); + sb.append( + " @Override\n" + + " public String getVersion() {\n" + + " return \"" ); + sb.append( Drools.getFullVersion() ); + sb.append( + "\";\n" + + " }\n" + + "\n" + + " @Override\n" + + " public java.util.List getModels() {\n" + + " return java.util.Arrays.asList(" ); + sb.append( modelSources.isEmpty() ? "" : modelSources.stream().collect( joining("(), new ", "new ", "()") ) ); + sb.append( + ");\n" + + " }\n" + + "\n" + + " @Override\n" + + " public ReleaseId getReleaseId() {\n" + + " return new ReleaseIdImpl(\"" ); + sb.append( releaseId.getGroupId() ).append( "\", \"" ); + sb.append( releaseId.getArtifactId() ).append( "\", \"" ); + sb.append( releaseId.getVersion() ).append( "\"" ); + sb.append( + ");\n" + + " }\n"); + sb.append("\n"); + sb.append(modelMethod.toGetKieModuleModelMethod()); + sb.append("\n}" ); + return sb.toString(); + } +} diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelWriter.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelWriter.java index f7ab52d838d..df69922c2d3 100644 --- a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelWriter.java +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ModelWriter.java @@ -53,6 +53,7 @@ public Result writeModel(MemoryFileSystem srcMfs, Collection packa String sourceName = "src/main/java/" + folderName + "/" + DOMAIN_CLASSESS_METADATA_FILE_NAME + pkgModel.getPackageUUID() + ".java"; addSource( srcMfs, sourceFiles, pkgModel, sourceName, pkgModel.getDomainClassesMetadataSource() ); + pkgModel.getModuleGenerator().write(srcMfs); } return new Result(sourceFiles, modelFiles); diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/PackageModel.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/PackageModel.java index 520c74e200a..5ee773ecbc0 100644 --- a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/PackageModel.java +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/PackageModel.java @@ -60,6 +60,7 @@ import org.drools.model.WindowReference; import org.drools.modelcompiler.builder.generator.DRLIdGenerator; import org.drools.modelcompiler.builder.generator.DrlxParseUtil; +import org.drools.modelcompiler.builder.generator.ModuleSourceClass; import org.drools.modelcompiler.builder.generator.QueryGenerator; import org.drools.modelcompiler.builder.generator.QueryParameter; import org.kie.api.runtime.rule.AccumulateFunction; @@ -72,6 +73,7 @@ import static org.drools.javaparser.ast.Modifier.finalModifier; import static org.drools.javaparser.ast.Modifier.publicModifier; import static org.drools.javaparser.ast.Modifier.staticModifier; +import static org.drools.modelcompiler.builder.generator.DrlxParseUtil.returnTypeOfMethodCallExpr; import static org.drools.modelcompiler.builder.generator.DrlxParseUtil.toClassOrInterfaceType; import static org.drools.modelcompiler.builder.generator.DrlxParseUtil.toVar; import static org.drools.modelcompiler.builder.generator.DslMethodNames.GLOBAL_OF_CALL; @@ -129,6 +131,7 @@ public class PackageModel { private KnowledgeBuilderConfigurationImpl configuration; private Map accumulateFunctions; private InternalKnowledgePackage pkg; + private ModuleSourceClass moduleGenerator; private final String pkgUUID = generateUUID(); @@ -325,6 +328,14 @@ public DialectCompiletimeRegistry getDialectCompiletimeRegistry() { return dialectCompiletimeRegistry; } + public void setModuleGenerator(ModuleSourceClass m) { + this.moduleGenerator = m; + } + + public ModuleSourceClass getModuleGenerator() { + return moduleGenerator; + } + public static class RuleSourceResult { private final CompilationUnit mainRuleClass; diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ProjectSourceClass.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ProjectSourceClass.java new file mode 100644 index 00000000000..b728da283e8 --- /dev/null +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/ProjectSourceClass.java @@ -0,0 +1,48 @@ +package org.drools.modelcompiler.builder; + +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.model.Model; +import org.kie.api.KieBase; +import org.kie.api.builder.model.KieBaseModel; +import org.kie.api.runtime.KieSession; + +public class ProjectSourceClass { + + final KieModuleModelMethod modelMethod; + + public ProjectSourceClass(KieModuleModelMethod modelMethod) { + this.modelMethod = modelMethod; + } + + public String generate() { + StringBuilder sb = new StringBuilder(); + sb.append( + "package org.drools.project.model;\n" + + "\n" + + "import " + Model.class.getCanonicalName() + ";\n" + + "import " + KieBase.class.getCanonicalName() + ";\n" + + "import " + KieBaseModel.class.getCanonicalName() + ";\n" + + "import " + KieSession.class.getCanonicalName() + ";\n" + + "\n" + + ( hasCdi() ? "@javax.enterprise.context.ApplicationScoped\n" : "" ) + + "public class ProjectRuntime implements org.drools.modelcompiler.KieRuntimeBuilder {\n" + + "\n"); + sb.append(modelMethod.getConstructor()); + sb.append("\n"); + sb.append(modelMethod.toNewKieSessionMethod()); + sb.append("\n"); + sb.append(modelMethod.toGetKieBaseForSessionMethod()); + sb.append("\n"); + sb.append(modelMethod.toKieSessionConfMethod()); + sb.append("\n}" ); + return sb.toString(); + } + + private boolean hasCdi() { + return true; + } + + public void write(MemoryFileSystem srcMfs) { + srcMfs.write(CanonicalModelKieProject.PROJECT_RUNTIME_SOURCE, generate().getBytes()); + } +} diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModelGenerator.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModelGenerator.java index 98dd60a7640..a68e295fa0a 100644 --- a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModelGenerator.java +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModelGenerator.java @@ -66,6 +66,7 @@ import org.drools.modelcompiler.builder.generator.expressiontyper.ExpressionTyper; import org.drools.modelcompiler.builder.generator.expressiontyper.ExpressionTyperContext; import org.drools.modelcompiler.builder.generator.visitor.ModelGeneratorVisitor; +import org.kie.api.runtime.rule.RuleUnit; import static java.util.stream.Collectors.toList; @@ -145,6 +146,8 @@ public static void generateModel(KnowledgeBuilderImpl kbuilder, InternalKnowledg } } + HashSet ruleUnitDescriptions = new HashSet<>(); + for (RuleDescr descr : packageDescr.getRules()) { RuleContext context = new RuleContext(kbuilder, packageModel, typeResolver, isPattern); context.setDialectFromAttributes(packageDescr.getAttributes()); @@ -152,8 +155,26 @@ public static void generateModel(KnowledgeBuilderImpl kbuilder, InternalKnowledg QueryGenerator.processQuery(kbuilder, packageModel, (QueryDescr) descr); } else { processRule(kbuilder, packageModel, packageDescr, descr, context); + RuleUnitDescription ruleUnitDescr = context.getRuleUnitDescr(); + if (ruleUnitDescr != null) ruleUnitDescriptions.add(ruleUnitDescr); } } + + ModuleSourceClass m = new ModuleSourceClass(); + + for (RuleUnitDescription rud : ruleUnitDescriptions) { + Class ruc = rud.getRuleUnitClass(); + + RuleUnitSourceClass rusc = new RuleUnitSourceClass( + ruc.getPackage().getName(), ruc.getSimpleName(), packageModel.getRulesFileName()); + RuleUnitInstanceSourceClass ruisc = new RuleUnitInstanceSourceClass( + ruc.getPackage().getName(), ruc.getSimpleName()); + + m.addRuleUnit(rusc); + m.addRuleUnitInstance(ruisc); + } + + packageModel.setModuleGenerator(m); } @@ -185,9 +206,10 @@ private static void processRule(KnowledgeBuilderImpl kbuilder, PackageModel pack } ruleCall.addArgument( new StringLiteralExpr( ruleDescr.getName() ) ); - MethodCallExpr buildCallScope = ruleUnitDescr != null ? - new MethodCallExpr(ruleCall, UNIT_CALL).addArgument( new ClassExpr( classToReferenceType(ruleUnitDescr.getRuleUnitClass()) ) ) : - ruleCall; + MethodCallExpr buildCallScope = ruleCall; +// ruleUnitDescr != null ? +// new MethodCallExpr(ruleCall, UNIT_CALL).addArgument( new ClassExpr( classToReferenceType(ruleUnitDescr.getRuleUnitClass()) ) ) : +// ruleCall; for (MethodCallExpr attributeExpr : ruleAttributes(context, ruleDescr)) { attributeExpr.setScope( buildCallScope ); diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModuleSourceClass.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModuleSourceClass.java new file mode 100644 index 00000000000..2656f4f7789 --- /dev/null +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/ModuleSourceClass.java @@ -0,0 +1,81 @@ +package org.drools.modelcompiler.builder.generator; + +import java.util.ArrayList; +import java.util.List; + +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.javaparser.ast.CompilationUnit; +import org.drools.javaparser.ast.Modifier; +import org.drools.javaparser.ast.body.ClassOrInterfaceDeclaration; +import org.drools.javaparser.ast.body.MethodDeclaration; +import org.drools.javaparser.ast.expr.ObjectCreationExpr; +import org.drools.javaparser.ast.stmt.BlockStmt; +import org.drools.javaparser.ast.stmt.ReturnStmt; +import org.drools.javaparser.ast.type.ClassOrInterfaceType; +import org.kie.submarine.rules.RuleUnit; + +public class ModuleSourceClass { + + private final String packageName; + private final String sourceFilePath; + private final String completePath; + private final String targetCanonicalName; + private final List ruleUnits; + private final List ruleUnitInstances; + private String targetTypeName; + + public ModuleSourceClass() { + this.packageName = "org.drools.project.model"; + this.targetTypeName = "Module"; + this.targetCanonicalName = packageName + "." + targetTypeName; + this.sourceFilePath = targetCanonicalName.replace('.', '/') + ".java"; + this.completePath = "src/main/java/" + sourceFilePath; + this.ruleUnits = new ArrayList<>(); + this.ruleUnitInstances = new ArrayList<>(); + } + + public void addRuleUnit(RuleUnitSourceClass rusc) { + ruleUnits.add(rusc); + } + + public void addRuleUnitInstance(RuleUnitInstanceSourceClass ruisc) { + ruleUnitInstances.add(ruisc); + } + + public void write(MemoryFileSystem srcMfs) { + ruleUnits.forEach(r -> r.write(srcMfs)); + ruleUnitInstances.forEach(r -> r.write(srcMfs)); + srcMfs.write(completePath, generate().getBytes()); + } + + public String generate() { + return compilationUnit().toString(); + } + + public CompilationUnit compilationUnit() { + CompilationUnit compilationUnit = new CompilationUnit(packageName); + ClassOrInterfaceDeclaration cls = + compilationUnit.addClass(targetTypeName); + + for (RuleUnitSourceClass r : ruleUnits) { + cls.addMember(ruleUnitFactoryMethod(r)); + } + + return compilationUnit; + } + + public static MethodDeclaration ruleUnitFactoryMethod(RuleUnitSourceClass r) { + return new MethodDeclaration() + .addModifier(Modifier.Keyword.PUBLIC) + .setName("create" + r.targetTypeName()) + .setType(r.targetCanonicalName()) + .setBody(new BlockStmt().addStatement(new ReturnStmt( + new ObjectCreationExpr() + .setType(r.targetCanonicalName())))); + } + + public static ClassOrInterfaceType ruleUnitType(String canonicalName) { + return new ClassOrInterfaceType(null, RuleUnit.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType(null, canonicalName)); + } +} diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitInstanceSourceClass.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitInstanceSourceClass.java new file mode 100644 index 00000000000..0af7749b996 --- /dev/null +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitInstanceSourceClass.java @@ -0,0 +1,72 @@ +package org.drools.modelcompiler.builder.generator; + +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.javaparser.ast.CompilationUnit; +import org.drools.javaparser.ast.Modifier; +import org.drools.javaparser.ast.body.ClassOrInterfaceDeclaration; +import org.drools.javaparser.ast.expr.MethodCallExpr; +import org.drools.javaparser.ast.expr.NameExpr; +import org.drools.javaparser.ast.stmt.BlockStmt; +import org.drools.javaparser.ast.type.ClassOrInterfaceType; +import org.kie.api.runtime.KieSession; +import org.kie.submarine.rules.impl.AbstractRuleUnitInstance; + +public class RuleUnitInstanceSourceClass { + + private final String packageName; + private final String typeName; + private final String canonicalName; + private final String targetTypeName; + private final String targetCanonicalName; + private final String sourceFilePath; + private final String completePath; + + public static String qualifiedName(String packageName, String typeName) { + return packageName + "." + typeName + "RuleUnitInstance"; + } + + public RuleUnitInstanceSourceClass(String packageName, String typeName) { + this.packageName = packageName; + this.typeName = typeName; + this.canonicalName = packageName + "." + typeName; + this.targetTypeName = typeName + "RuleUnitInstance"; + this.targetCanonicalName = packageName + "." + targetTypeName; + this.sourceFilePath = targetCanonicalName.replace('.', '/') + ".java"; + this.completePath = "src/main/java/" + sourceFilePath; + } + + public void write(MemoryFileSystem srcMfs) { + srcMfs.write(completePath, generate().getBytes()); + } + + public String generate() { + return compilationUnit().toString(); + } + + public CompilationUnit compilationUnit() { + CompilationUnit compilationUnit = new CompilationUnit(packageName); + compilationUnit.getTypes().add(classDeclaration()); + return compilationUnit; + } + + public ClassOrInterfaceDeclaration classDeclaration() { + ClassOrInterfaceDeclaration classDecl = new ClassOrInterfaceDeclaration() + .setName(targetTypeName) + .addModifier(Modifier.Keyword.PUBLIC); + classDecl + .addExtendedType( + new ClassOrInterfaceType(null, AbstractRuleUnitInstance.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType(null, canonicalName))) + .addConstructor(Modifier.Keyword.PUBLIC) + .addParameter(RuleUnitSourceClass.ruleUnitType(canonicalName), "unit") + .addParameter(canonicalName, "value") + .addParameter(KieSession.class.getCanonicalName(), "session") + .setBody(new BlockStmt().addStatement(new MethodCallExpr( + "super", + new NameExpr("unit"), + new NameExpr("value"), + new NameExpr("session") + ))); + return classDecl; + } +} diff --git a/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitSourceClass.java b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitSourceClass.java new file mode 100644 index 00000000000..2809f2150e6 --- /dev/null +++ b/drools/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/builder/generator/RuleUnitSourceClass.java @@ -0,0 +1,131 @@ +package org.drools.modelcompiler.builder.generator; + +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.javaparser.ast.CompilationUnit; +import org.drools.javaparser.ast.Modifier; +import org.drools.javaparser.ast.body.ClassOrInterfaceDeclaration; +import org.drools.javaparser.ast.body.MethodDeclaration; +import org.drools.javaparser.ast.expr.MethodCallExpr; +import org.drools.javaparser.ast.expr.NameExpr; +import org.drools.javaparser.ast.expr.ObjectCreationExpr; +import org.drools.javaparser.ast.expr.ThisExpr; +import org.drools.javaparser.ast.stmt.BlockStmt; +import org.drools.javaparser.ast.stmt.ReturnStmt; +import org.drools.javaparser.ast.type.ClassOrInterfaceType; +import org.kie.submarine.rules.RuleUnit; +import org.kie.submarine.rules.impl.AbstractRuleUnit; + +import static org.drools.javaparser.ast.NodeList.nodeList; + +public class RuleUnitSourceClass { + + private final String packageName; + private final String typeName; + private final String generatedSourceFile; + private final String sourceFilePath; + private final String completePath; + private final String canonicalName; + private final String targetCanonicalName; + private String targetTypeName; + + public RuleUnitSourceClass(String packageName, String typeName, String generatedSourceFile) { + this.packageName = packageName; + this.typeName = typeName; + this.generatedSourceFile = generatedSourceFile; + this.canonicalName = packageName + "." + typeName; + this.targetTypeName = typeName + "RuleUnit"; + this.targetCanonicalName = packageName + "." + targetTypeName; + this.sourceFilePath = targetCanonicalName.replace('.', '/') + ".java"; + this.completePath = "src/main/java/" + sourceFilePath; + } + + public String targetCanonicalName() { + return targetCanonicalName; + } + + public String targetTypeName() { + return targetTypeName; + } + + public void write(MemoryFileSystem srcMfs) { + srcMfs.write(completePath, generate().getBytes()); + } + + public String generate() { + return compilationUnit().toString(); + } + + public CompilationUnit compilationUnit() { + CompilationUnit compilationUnit = new CompilationUnit(packageName); + compilationUnit.getTypes().add(classDeclaration()); + return compilationUnit; + } + + private MethodDeclaration createInstanceMethod(String ruleUnitInstanceFQCN) { + MethodDeclaration methodDeclaration = new MethodDeclaration(); + + ReturnStmt returnStmt = new ReturnStmt( + new ObjectCreationExpr() + .setType(ruleUnitInstanceFQCN) + .setArguments(nodeList( + new ThisExpr(), + new NameExpr("value"), + newKieSession()))); + + methodDeclaration.setName("createInstance") + .addModifier(Modifier.Keyword.PUBLIC) + .addParameter(canonicalName, "value") + .setType(ruleUnitInstanceFQCN) + .setBody(new BlockStmt() + .addStatement(returnStmt) + ); + return methodDeclaration; + } + + private MethodCallExpr newKieSession() { + /* + KieBaseBuilder.createKieBaseFromModel( + asList(new $GENERATED_RULE_ID(), ...)) + .newKieSession(); + */ + MethodCallExpr createKieBaseFromModel = createKieBaseFromModel(); + return new MethodCallExpr(createKieBaseFromModel, "newKieSession"); + } + + private MethodCallExpr createKieBaseFromModel() { + MethodCallExpr args = args(); + + return new MethodCallExpr( + new NameExpr("org.drools.modelcompiler.builder.KieBaseBuilder"), + "createKieBaseFromModel").addArgument(args); + } + + private MethodCallExpr args() { + return new MethodCallExpr( + new NameExpr("java.util.Collections"), + "singletonList").addArgument(new ObjectCreationExpr().setType(generatedSourceFile)); + } + + public static ClassOrInterfaceType ruleUnitType(String canonicalName) { + return new ClassOrInterfaceType(null, RuleUnit.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType(null, canonicalName)); + } + + public static ClassOrInterfaceType abstractRuleUnitType(String canonicalName) { + return new ClassOrInterfaceType(null, AbstractRuleUnit.class.getCanonicalName()) + .setTypeArguments(new ClassOrInterfaceType(null, canonicalName)); + } + + public ClassOrInterfaceDeclaration classDeclaration() { + ClassOrInterfaceDeclaration cls = new ClassOrInterfaceDeclaration() + .setName(targetTypeName) + .setModifiers(Modifier.Keyword.PUBLIC) + .addAnnotation("javax.enterprise.context.ApplicationScoped"); + String ruleUnitInstanceFQCN = RuleUnitInstanceSourceClass.qualifiedName(packageName, typeName); + + MethodDeclaration methodDeclaration = createInstanceMethod(ruleUnitInstanceFQCN); + cls.addExtendedType(abstractRuleUnitType(canonicalName)) + .addMember(methodDeclaration); + return cls; + } +} diff --git a/kie-maven-plugin/pom.xml b/kie-maven-plugin/pom.xml index 8b68b53c826..42ae5813157 100644 --- a/kie-maven-plugin/pom.xml +++ b/kie-maven-plugin/pom.xml @@ -122,19 +122,37 @@ org.drools drools-core + + + org.drools + drools-core-dynamic + + + com.thoughtworks.xstream + xstream + + + org.drools - drools-core-reflective - - - org.drools - drools-compiler + drools-core-static org.drools drools-model-compiler + + + org.drools + drools-core-dynamic + + + com.thoughtworks.xstream + xstream + + + org.kie kie-api diff --git a/kie-maven-plugin/src/main/java/org/kie/maven/plugin/CanonicalModelWriter.java b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/CanonicalModelWriter.java new file mode 100644 index 00000000000..fc168cc8d86 --- /dev/null +++ b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/CanonicalModelWriter.java @@ -0,0 +1,66 @@ +package org.kie.maven.plugin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.drools.compiler.compiler.io.memory.MemoryFile; +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; + +public class CanonicalModelWriter { + + private MemoryFileSystem mfs; + private Collection fileNames; + private final String droolsModelCompilerOutputDirectory; + private final Log log; + + public CanonicalModelWriter( + MemoryFileSystem mfs, + Collection fileNames, + String droolsModelCompilerOutputDirectory, + Log log) { + this.mfs = mfs; + this.fileNames = fileNames; + this.droolsModelCompilerOutputDirectory = droolsModelCompilerOutputDirectory; + this.log = log; + } + + public void write() throws MojoExecutionException { + List generatedFiles = fileNames + .stream() + .filter(f -> f.endsWith("java")) + .collect(Collectors.toList()); + + log.info(String.format("Found %d generated files in Canonical Model", generatedFiles.size())); + + List ff = fileNames + .stream() + .filter(f -> f.endsWith("java")) + .map(mfs::getFile) + .map(MemoryFile.class::cast) + .collect(Collectors.toList()); + + for (MemoryFile f : ff) { + final Path newFile = Paths.get(droolsModelCompilerOutputDirectory, + f.getPath().toPortableString()); + + try { + Files.deleteIfExists(newFile); + Files.createDirectories(newFile.getParent()); + Files.copy(f.getContents(), newFile, StandardCopyOption.REPLACE_EXISTING); + + log.info("Generating " + newFile); + } catch (IOException e) { + e.printStackTrace(); + throw new MojoExecutionException("Unable to write file", e); + } + } + } +} diff --git a/kie-maven-plugin/src/main/java/org/kie/maven/plugin/GenerateModelMojo.java b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/GenerateModelMojo.java index c8c6d74fa33..94e9395bdbe 100644 --- a/kie-maven-plugin/src/main/java/org/kie/maven/plugin/GenerateModelMojo.java +++ b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/GenerateModelMojo.java @@ -9,16 +9,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -33,11 +29,9 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -import org.drools.compiler.compiler.io.memory.MemoryFile; import org.drools.compiler.compiler.io.memory.MemoryFileSystem; import org.drools.compiler.kie.builder.impl.InternalKieModule; import org.drools.compiler.kie.builder.impl.KieBuilderImpl; -import org.drools.compiler.kie.builder.impl.KieModuleKieProject; import org.drools.compiler.kie.builder.impl.MemoryKieModule; import org.drools.compiler.kie.builder.impl.ResultsImpl; import org.drools.compiler.kie.builder.impl.ZipKieModule; @@ -48,11 +42,15 @@ import org.drools.modelcompiler.builder.KieModuleModelMethod; import org.drools.modelcompiler.builder.ModelBuilderImpl; import org.drools.modelcompiler.builder.ModelWriter; +import org.drools.modelcompiler.builder.ProjectSourceClass; +import org.drools.modelcompiler.builder.generator.ModuleSourceClass; +import org.drools.modelcompiler.builder.generator.RuleUnitInstanceSourceClass; +import org.drools.modelcompiler.builder.generator.RuleUnitSourceClass; import org.kie.api.KieServices; -import org.kie.api.builder.KieBuilder; import org.kie.api.builder.ReleaseId; import org.kie.api.builder.model.KieModuleModel; +import static java.util.Collections.singletonList; import static org.drools.compiler.kie.builder.impl.KieBuilderImpl.setDefaultsforEmptyKieModule; @Mojo(name = "generateModel", @@ -81,6 +79,12 @@ public class GenerateModelMojo extends AbstractKieMojo { @Parameter(required = true, defaultValue = "${project.build.outputDirectory}") private File outputDirectory; + @Parameter(defaultValue = "${project.build.directory}/generated-sources/drools-model-compiler") + private File modelCompilerOutputDirectory; + + @Parameter(defaultValue = "${project.source.directory}") + private File projectSourceDirectory; + @Parameter(property = "generateModel", defaultValue = "no") private String generateModel; @@ -93,12 +97,57 @@ public void execute() throws MojoExecutionException, MojoFailureException { private void generateModel() throws MojoExecutionException { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + KieServices ks = KieServices.Factory.get(); - List kmoduleDeps = new ArrayList<>(); + try { + ClassLoader projectClassLoader = createProjectClassLoader(); - KieServices ks = KieServices.Factory.get(); + Thread.currentThread().setContextClassLoader(projectClassLoader); + + setSystemProperties(properties); + + final KieBuilderImpl kieBuilder = (KieBuilderImpl) ks.newKieBuilder(projectDir); + + getLog().info("Begin code generation"); + + kieBuilder.buildAll(ExecutableModelMavenPluginKieProject::new, s -> { + return !s.contains("src/test/java"); + }); + + InternalKieModule kieModule = (InternalKieModule) kieBuilder.getKieModule(); + getLog().info("kieBuilder is type: "+kieBuilder.getClass()); + getLog().info("kieModule is type: "+kieModule.getClass()); + MemoryFileSystem mfs = getMemoryFileSystem(kieModule); + + String modelCompilerOutputPath = + modelCompilerOutputDirectory.getPath(); + + new CanonicalModelWriter( + mfs, + kieModule.getFileNames(), + modelCompilerOutputPath, + getLog()).write(); + project.addCompileSourceRoot(modelCompilerOutputPath); + + new ResourceFileWriter( + mfs, + targetDirectory.getPath()).write(); + + if (ExecModelMode.shouldDeleteFile(generateModel)) { + deleteDrlFiles(); + } + } finally { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + + getLog().info("DSL successfully generated"); + } + + private ClassLoader createProjectClassLoader() throws MojoExecutionException { try { + List kmoduleDeps = new ArrayList<>(); + Set urls = new HashSet<>(); for (String element : project.getCompileClasspathElements()) { urls.add(new File(element).toURI().toURL()); @@ -123,79 +172,17 @@ private void generateModel() throws MojoExecutionException { } urls.add(outputDirectory.toURI().toURL()); - ClassLoader projectClassLoader = URLClassLoader.newInstance(urls.toArray(new URL[0]), - getClass().getClassLoader()); - - Thread.currentThread().setContextClassLoader(projectClassLoader); + return URLClassLoader.newInstance(urls.toArray(new URL[0]), + getClass().getClassLoader()); } catch (DependencyResolutionRequiredException | MalformedURLException e) { - throw new RuntimeException(e); - } - - try { - setSystemProperties(properties); - - final KieBuilderImpl kieBuilder = (KieBuilderImpl) ks.newKieBuilder(projectDir); - kieBuilder.buildAll(ExecutableModelMavenProject.SUPPLIER, s -> { - return !s.contains("src/test/java"); - }); - - InternalKieModule kieModule = (InternalKieModule) kieBuilder.getKieModule(); - List generatedFiles = kieModule.getFileNames() - .stream() - .filter(f -> f.endsWith("java")) - .collect(Collectors.toList()); - - getLog().info(String.format("Found %d generated files in Canonical Model", generatedFiles.size())); - - MemoryFileSystem mfs = kieModule instanceof CanonicalKieModule ? - ((MemoryKieModule) ((CanonicalKieModule) kieModule).getInternalKieModule()).getMemoryFileSystem() : - ((MemoryKieModule) kieModule).getMemoryFileSystem(); - - final String droolsModelCompilerPath = "/generated-sources/drools-model-compiler/main/java"; - final String newCompileSourceRoot = targetDirectory.getPath() + droolsModelCompilerPath; - project.addCompileSourceRoot(newCompileSourceRoot); - - for (String generatedFile : generatedFiles) { - final MemoryFile f = (MemoryFile) mfs.getFile(generatedFile); - final Path newFile = Paths.get(targetDirectory.getPath(), - droolsModelCompilerPath, - f.getPath().toPortableString()); - - try { - Files.deleteIfExists(newFile); - Files.createDirectories(newFile.getParent()); - Files.copy(f.getContents(), newFile, StandardCopyOption.REPLACE_EXISTING); - - getLog().info("Generating " + newFile); - } catch (IOException e) { - e.printStackTrace(); - throw new MojoExecutionException("Unable to write file", e); - } - } - - // copy the META-INF packages file - final MemoryFile packagesMemoryFile = (MemoryFile) mfs.getFile(CanonicalKieModule.MODEL_FILE); - final String packagesMemoryFilePath = packagesMemoryFile.getFolder().getPath().toPortableString(); - final Path packagesDestinationPath = Paths.get(targetDirectory.getPath(), "classes", packagesMemoryFilePath, packagesMemoryFile.getName()); - - try { - if (!Files.exists(packagesDestinationPath)) { - Files.createDirectories(packagesDestinationPath.getParent()); - } - Files.copy(packagesMemoryFile.getContents(), packagesDestinationPath, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); - throw new MojoExecutionException("Unable to write file", e); - } - - if (ExecModelMode.shouldDeleteFile(generateModel)) { - deleteDrlFiles(); - } - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); + throw new MojoExecutionException("Error setting up Kie ClassLoader", e); } + } - getLog().info("DSL successfully generated"); + private MemoryFileSystem getMemoryFileSystem(InternalKieModule kieModule) { + return kieModule instanceof CanonicalKieModule ? + ((MemoryKieModule) ((CanonicalKieModule) kieModule).getInternalKieModule()).getMemoryFileSystem() : + ((MemoryKieModule) kieModule).getMemoryFileSystem(); } private void deleteDrlFiles() throws MojoExecutionException { @@ -238,33 +225,31 @@ private KieModuleModel getDependencyKieModel(File jar) { return null; } - public static class ExecutableModelMavenProject implements KieBuilder.ProjectType { - - public static final BiFunction SUPPLIER = ExecutableModelMavenPluginKieProject::new; + private class ExecutableModelMavenPluginKieProject extends CanonicalModelKieProject { - public static class ExecutableModelMavenPluginKieProject extends CanonicalModelKieProject { + public ExecutableModelMavenPluginKieProject(InternalKieModule kieModule, ClassLoader classLoader) { + super(true, kieModule, classLoader); + } - public ExecutableModelMavenPluginKieProject(InternalKieModule kieModule, ClassLoader classLoader) { - super(true, kieModule, classLoader); + @Override + public void writeProjectOutput(MemoryFileSystem trgMfs, ResultsImpl messages) { + MemoryFileSystem srcMfs = new MemoryFileSystem(); + List generatedSourceFiles = new ArrayList<>(); + ModelWriter modelWriter = new ModelWriter(); + for (ModelBuilderImpl modelBuilder : modelBuilders) { + ModelWriter.Result result = modelWriter.writeModel(srcMfs, modelBuilder.getPackageModels()); + generatedSourceFiles.addAll(result.getModelFiles()); } - @Override - public void writeProjectOutput(MemoryFileSystem trgMfs, ResultsImpl messages) { - MemoryFileSystem srcMfs = new MemoryFileSystem(); - List modelFiles = new ArrayList<>(); - ModelWriter modelWriter = new ModelWriter(); - for (ModelBuilderImpl modelBuilder : modelBuilders) { - ModelWriter.Result result = modelWriter.writeModel(srcMfs, modelBuilder.getPackageModels()); - modelFiles.addAll(result.getModelFiles()); - } - - KieModuleModelMethod modelMethod = new KieModuleModelMethod(kBaseModels); - srcMfs.write(PROJECT_MODEL_SOURCE, buildModelSourceClass( modelMethod, modelFiles ).getBytes()); - srcMfs.write( PROJECT_RUNTIME_SOURCE, buildProjectSourceClass( modelMethod ).getBytes()); + KieModuleModelMethod modelMethod = new KieModuleModelMethod(kBaseModels); + new org.drools.modelcompiler.builder.ModelSourceClass( + getInternalKieModule().getReleaseId(), modelMethod, generatedSourceFiles) + .write(srcMfs); + new ProjectSourceClass(modelMethod) + .write(srcMfs); - srcMfs.copyFolder(srcMfs.getFolder("src/main/java"), trgMfs, trgMfs.getFolder(".")); - writeModelFile(modelFiles, trgMfs); - } + srcMfs.copyFolder(srcMfs.getFolder("src/main/java"), trgMfs, trgMfs.getFolder(".")); + writeModelFile(generatedSourceFiles, trgMfs); } } } diff --git a/kie-maven-plugin/src/main/java/org/kie/maven/plugin/ResourceFileWriter.java b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/ResourceFileWriter.java new file mode 100644 index 00000000000..7ab1415eb8d --- /dev/null +++ b/kie-maven-plugin/src/main/java/org/kie/maven/plugin/ResourceFileWriter.java @@ -0,0 +1,40 @@ +package org.kie.maven.plugin; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import org.apache.maven.plugin.MojoExecutionException; +import org.drools.compiler.compiler.io.memory.MemoryFile; +import org.drools.compiler.compiler.io.memory.MemoryFileSystem; +import org.drools.modelcompiler.CanonicalKieModule; + +public class ResourceFileWriter { + + private MemoryFileSystem mfs; + private String targetDirectory; + + public ResourceFileWriter(MemoryFileSystem mfs, String targetDirectory) { + this.mfs = mfs; + this.targetDirectory = targetDirectory; + } + + public void write() throws MojoExecutionException { + // copy the META-INF packages file + final MemoryFile packagesMemoryFile = (MemoryFile) mfs.getFile(CanonicalKieModule.MODEL_FILE); + final String packagesMemoryFilePath = packagesMemoryFile.getFolder().getPath().toPortableString(); + final Path packagesDestinationPath = Paths.get(targetDirectory, "classes", packagesMemoryFilePath, packagesMemoryFile.getName()); + + try { + if (!Files.exists(packagesDestinationPath)) { + Files.createDirectories(packagesDestinationPath.getParent()); + } + Files.copy(packagesMemoryFile.getContents(), packagesDestinationPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + throw new MojoExecutionException("Unable to write file", e); + } + } +}