drools-6 (kie) auto scanning (from spring) of modules and sessions from kie workbench deployed artifacts - spring

I am trying to build a web (spring-mvc) application with kie (drools 6) integrated via injection. I have used kie workbench to create a workflow, complied and deployed. I have added reference of this artifact in my project's pom.xml and added the local kie-workbench repository as per this blog post and it's working fine (pulling in the artifact as dependency in my maven/spring project). What I am trying to do is inject the kiesession in one of my service as dependency with following snippet -
#Service
public class TniServiceImpl implements TniService {
#Inject
#KSession("tniSession")
private KieSession tniSession;
...
}
In my root-context.xml, I have added the kie namespace as well along with reference to xsd. I have added org.kie.spring.KModuleBeanFactoryPostProcessor as well as per drools documentation. I am trying to make CDI injection work for KSession scanning and injection (it's already working for my other components in same project, using #Inject). So far I am always getting "No qualifying bean of type [org.kie.api.runtime.KieSession] found for dependency" error. Looks like spring is not able to scan the available kie modules and sessions therein. Need help on following -
Is CDI inject really supported with spring? Do I have to configure kmodules and kession explicitly as mentioned here?
Am I missing something here which should make this scanning and injection work?
My environment is following -
spring 3.2.6-RELEASE (including webmvc and other components)
kie-api-6.0.1.FINAL
kie-spring-6.0.1.FINAL
kie-internal-6.0.1.FINAL
I have already gone through following links but no luck (mostly they are not trying to do what I am) -
Loading Drools/KIE Workbench artifacts directly from the repository
why does loading Drools 6 KIE JAR into code fail?
I'll appreciate if anybody can guide me on what could be the missing piece here or if there's no option but to explicitly define all kmodules/ksessions in spring config file.

I had the same problem and found a solution here: http://drools.46999.n3.nabble.com/Spring-4-0-amp-Drools-6-0-1-Integration-issue-td4028052.html
Basically you will need to inject ApplicationContext instead of kieSession and get xml bean manually.
TniServiceImpl.java
#Service
public class TniServiceImpl implements TniService {
#Inject
ApplicationContext context;
KieSession kieSession;
#PostConstruct
public void postConstruct(){
kieSession = (KieSession) context.getBean("ksession1");
}
...
}
root-context.xml
<kie:kmodule id="kmodule1">
<kie:kbase name="kbase1">
<kie:ksession name="ksession1" />
</kie:kbase>
</kie:kmodule>
<bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor" />
Hope this helps.
UPDATE:
Another way to achieve this is to keep xml identical and instead of trying to inject KieSession, inject KieBase. Then, with the instance of KieBase, create new KieSessions.
#Service
public class TniServiceImpl implements TniService {
#Autowired
private KieBase kbase;
/* inside some method */
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody Data getData() {
KieSession ksession = kbase.newKieSession();
...
}
}

The above answer doesn't work with spring mvc. I found that this is a bug in the existing drools and they are fixing it in the next version. I am stuck at this point since I am using DROOLS in batch mode but I want it to be used in a REST Service hosted on websphere.
The above solution works perfectly within a batch program.

This is what I have working with the latest Spring MVC (Spring Boot)
#SpringBootApplication
public class DroolDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DroolDemoApplication.class, args);
}
#Bean
public KieContainer kieContainer() {
return KieServices.Factory.get().getKieClasspathContainer();
}
#Bean
public KieSession kieSession() throws IOException {
return kieContainer().newKieSession("DroolDemoSession");
}
}
and below is the kmodule.xml
<kbase name="DroolDemoKbase" packages="rules">
<ksession name="DroolDemoSession" />
</kbase>
finally all you do in your controller is
#Autowired
private KieSession kieSession;
kieSession.fireAllRules();
hope this helps those folks still having issues

I had similar issues with the rules not being triggered, and I solved it by using the 6.2.0.Final version of the kie-ci and kie-spring. I tried versions: 7.7.0, 7.2.0, 6.5.0 and 6.4.0, but none of them worked.
...
<properties>
<kie.version>6.2.0.Final</kie.version>
</properties>
...
<dependencies>
...
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-ci</artifactId>
<version>${kie.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${kie.version}</version>
</dependency>
...
</dependencies>
What also helped was running mvn dependency:tree and seeing which versions of which artefacts/projects are being used.

Related

Spring-boot listener’s #autowire is not work on recent versions

Spring-boot listener’s #autowire is not work on recent versions
When using 2.3.1.RELEASE of Spring-boot everything is ok.
#WebListener
public class Listener implements ServletContextListener {
#Autowired private Environment env;
#Override public void contextInitialized(ServletContextEvent sce) { try { if (env == null) // is false
When using 2.6.2 of Spring-boot the env will be null
change pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version><!-- ******** 2.3.1.RELEASE - 2.6.2 ********** -->
<relativePath/>
</parent>
sample code is in this link
as an issue I created in the spring-boot project in GitHub, this is due to the changes in Spring Boot 2.4 to allow #WebListeners to register servlets and filters. The change in 2.4 requires the Servlet container to be responsible for creating the listener so Spring-based dependency injection is no longer available.
Generally speaking, #ServletComponentScan is intended for registering third-party components where you can't modify the code. If you're in a position to use #Autowired and the like then you should use #Component. An exception to this is where you need to be able to register servlets and filters from your listener. #WebListener should be used in this case.
result of this issue updated the release notes for 2.4.

Deploy Spring Boot (with JSP) to Elastic Beanstalk

I am attempting to deploy my Spring Boot project to Amazon Elastic Beanstalk. I have tested and have no issue if I use the default Thymeleaf configuration, but when I switch to JSP based setup I get 404's as it cannot find the JSP's (located in src/main/webapp/WEB-INF/jsp)
I have attempted to deploy the sample (spring-boot-sample-tomcat-jsp) and find that this as well gives me a 404 when I run the provided test.
Here is how I have typically been configuring my Spring Boot Projects to allow for the use of JSP's.
Add Jasper and JSTL to pom.xml
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
Override default view resolver configuration
#Configuration
#EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter
{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
Create folder for JSP's (src/main/webapp/WEB-INF/jsp)
Now this method works without issue until I deploy to Elastic Beanstalk where I find that no matter if I create a jar and use Java (in Elastic Beanstalk) or create a war and use Tomcat (in eb) I get a 404 when any controller tries to return a view in the WEB-INF/jsp folder.
Is the above method for switching to JSP's not recommended? Is there a better way to configure Spring Boot to use Tomcat/Jasper/JSP's?
I have attempted the method provided in the Spring Boot Samples on github here
But what's interesting is if I run the provided test i get the same 404.
Any help would be greatly appreciated. If there is a better way to deploy a Spring Boot project that utilizes JSP's I'd be happy to switch over, but currently I seem to have configured myself into a corner.
Thx!
I am answering as a novice developer in Springboot development. And, I am just playing around with AWS EB and SpringBoot app deployment.
Here are my findings,
WebMvcConfigurerAdapter is deprecated
SpringBoot app works seamlessly on AWS EB only when we extend application/main class with SpringBootServletInitializer
I tried a sample HelloWorld application extending WebMvcConfigurerAdapter, which worked seamlessly on localhost and failed miserable on AWS EB.
I switched the application class extending from WebMvcConfigurerAdapter to SpringBootServletInitializer, this worked on both localhost as well as AWS EB.
The example I tried is inspired from here: https://github.com/in28minutes/deploy-spring-boot-aws-eb/tree/master/03-spring-boot-web-application-h2
Here is the application class that I changed from extending SpringBootServletInitializer to WebMvcConfigurerAdapter, which didn't work and gave me 404.
https://github.com/in28minutes/deploy-spring-boot-aws-eb/blob/master/03-spring-boot-web-application-h2/src/main/java/com/in28minutes/springboot/web/SpringBootFirstWebApplication.java
Hopefully this helps ...!
Still finding out a reason about why we receive 404 when we extend Application class with WebMvcConfigurerAdapter. I Will update this same answer, once I find a reason.
Thank you...!

Convert a Spring MVC application to Spring Boot - BeanCurrentlyInCreationException issue

I have a Spring MVC application, using Hibernate for my entities persistence management. I am able to build, deploy and run it on some application server such as glashfish or tomcat, all is fine.
Now, I want to convert it into a Spring Boot application. I added the following class:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(Application.class, args);
}
}
and added the spring-boot, spring-boot-autoconfigure, and spring-boot-starter-tomcat dependencies to my pom.
Alas, when trying to run the application, I get the following error:
BeanCurrentlyInCreationException: Error creating bean with name
'MyClassDAO': Bean with name 'MyClassDAO' has been injected into
other beans [MyOtherClassDAO] in its raw version as part of a circular
reference, but has eventually been wrapped. This means that said other
beans do not use the final version of the bean. This is often the result
of over-eager type matching - consider using 'getBeanNamesOfType' with
the 'allowEagerInit' flag turned off, for example.
I don't know how to use 'getBeanNamesOfType' and set the allowEagerInit off (I do not use XML configuration). Of course, I'm not sure this would solve my issue anyway.
Any ideas on how I can fix this?
If it's really some intilization issue then i believe the you must be having your class in other package and due to some cache issues it doesn't include those classes in class path to scan in container so to do this manually you can put a annotation just below #springbootapllication is #EnableComponentScan("enter the package name of the class which is not initializing") also on that dao class put #service or #component annotation to let the application include then in container

Integrating Spring XML beans from external jar into a CDI application

I have a new CDI Java EE application running on WebSphere. Now I want to use an existing module (.jar) in my CDI project, however the existing module uses Spring with Spring annotations and an Spring XML configuration file with additional bean definitions in it. Normally I would just import the Spring XML in my project, but in the CDI application this will not work.
I tried to load the Spring XML using JBoss Seam, like so:
#Produces
#SpringContext
#Configuration(locations = "classpath*:external-spring--context.xml")
ApplicationContext context;
But the context is null? I cannot realy find good examples on how to do this, help is much appreciated :)
I solved it by adding an CDI producer that will create the Spring context using the spring XML file:
public class SpringBeansFactory {
#Inject
ApplicationContext context;
#Produces
public BusinesService getBusinessService() {
return context.getBean(BusinesService.class);
}
}
class SpringContextFactory {
#Produces
public ApplicationContext getApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:spring-context.xml");
}
}

Plugin System in Spring Boot for modular applications

I looking for dynamically loading jar in spring boot after compiling, for example I will put jars in some folder and when spring boot is started, all jars from this folder will be injected into spring boot app. I don't know how can I do this with spring boot, and if You know can help me with this, with some example.
I need this jars to have #Service, #Controller as this will be module (plugin), with adding capabilities to my spring boot app.
Is possible to do this with spring boot, and if it is possible, please provide me with some sample code.
Thanks in advance.
UPDATE:
I found something https://www.youtube.com/watch?v=F-sw2pFdcDw https://code.google.com/p/jspf/
UPDATE 2: I can't get #Controller bean from plugin jar registered in Spring Boot
Have a look at FlexiCore, an open-source framework that brings modularity to spring boot utilizing plugins(jars) loaded at runtime See wizzdi and FlexiCore.
for example FlexiCore allows you to create a project ( compiled into a seperate jar from your main application) that contains a spring bean as follows:
#Component
#Extension
public class HelloWorldService implements ServicePlugin{
public String hello() {
return "Hello World!";
}
}
it will be automatically be loaded once placed inside the designated plugins folder, it basically allows a full support for most(all) of spring boot features , so for example you can add a RestController bean to your jar as well , FlexiCore will automatically load that bean allowing you to call the controller as if it was in your main application jar:
#RestController
#Extension
public class TestEntityController implements Plugin {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#Autowired
private TestEntityService testEntityService;
#PostMapping("/createTestEntity")
public TestEntity createTestEntity(#RequestParam(name="name", required=false, defaultValue="Stranger") String name) {
return testEntityService.createTestEntity(name);
}
#GetMapping("{id}")
public TestEntity getTestEntity(#PathVariable("id")String id) {
return testEntityService.getTestEntity(id);
}
}
Disclaimer: I am the CTO of wizzdi, the company powering FlexiCore.
One option is definitely to just use broad #ComponentScan. If you add new jar to classpath the annotated classes from that jar will get discovered via #ComponentScan, #Controllers will get mapped etc.
The XML equivalent here would be placing xml configuration files somewhere to your classpath (META-INF folder being obvious choice) and import them all using wildcard. The idea is the same. If the plugin jar file is on classpath you will get the xml file imported and the beans (controllers, ...) will get loaded.
There are drawbacks to this approach like the modules not being isolated but its definitely option for simpler applications.
You can find a sample spring boot web project here.
By dynamically loading jars I assume you want to add dependencies to your project. For this you can update pom.xml of the sample project and put your dependencies here.

Resources