Search code examples
spring-mvcdroolskiedrools-kie-server

How to scan dtable drool file if there is any changes in file and load it again using kiescanner drool version 7.4..final


I am working on drool dtable xls file with spring. i have implemented the business rules in xls file using external location and then with the help of kie services i am executing rules. Following is the code snippet that's how i am loading rules in engine. at the start of spring initialization i am calling init() method see below spring configuration.

<bean id="droolsService" class="com.example.drools.DroolsServiceImpl" init-method="init">

Java Code

public void init() {
    LOG.info("inside init");
    KieSession kieSession;
    for (RequestType type : droolsMap.keySet()) {
        try {

            kieSession = getKieSession(this.getDroolsMap().get(type));
            droolsRules.put(type, kieSession);

        } catch (Exception e) {
            LOG.error("Failed to load kiesession:", e);
            throw new RuntimeException(e);
        }

    }

}


private KieSession getKieSession(final String file) throws DroolsParserException, IOException, BiffException {
    KieServices kieServices = KieServices.Factory.get();
    KieFileSystem kfs = kieServices.newKieFileSystem();

    InputStream stream = null;
    String drl = null;
    String RULE_PATH = "src/main/resources/";

    SpreadsheetCompiler converter = new SpreadsheetCompiler();

    //Workbook workbook = Workbook.getWorkbook(DroolsServiceImpl.class.getResourceAsStream(file));
    Workbook workbook = Workbook.getWorkbook(new FileInputStream(file));

    LOG.info("Loading rule file " + file);


    for (Sheet sheet : workbook.getSheets()) {
        LOG.info("Loading Sheet " + sheet.getName());
        stream = new FileInputStream(file);
        drl = converter.compile(stream, sheet.getName());
        //StringReader reader = new StringReader(drl);
        String DRL_FILE = RULE_PATH + sheet.getName() + ".drl";
        System.out.println("Drool file added ::: " + DRL_FILE);
        kfs.write(DRL_FILE, ResourceFactory.newReaderResource(new StringReader(drl)));
        stream.close();
    }

    KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
    KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
    KieSessionConfiguration conf = SessionConfiguration.newInstance();
    KieSession ksession = kieContainer.newKieSession(conf);
    if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
        List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
        StringBuilder sb = new StringBuilder("Errors:");
        for (Message msg : errors) {
            sb.append("\n  " + msg);
        }
        try {
            throw new Exception(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (stream != null)
                stream.close();
            if (workbook != null)
                workbook.close();
        }
    }
    return ksession;
}

Everything working perfect but the problem is i am not able to scan the file changes. If files is modified then i have to restart the server in order to sync the changes.

I have tried listener to load specific init() method after xls dtable has any changes but its not working , same old result is coming.

I have tried kiescanner but i am not able to get the concept. KieScanner is loading maven kjar so how do i suppose to create kjar.

I just wanted to kie api scan if any changes in the drool file and try to reload whole changes in kiecontainer without server restarting.


Solution

  • Found the answer myself, Posting because it will help someone who needed.

    What I did , I have used apache VFS File Monitor-

    DefaultFileMonitor fm = new DefaultFileMonitor(new CustomFileListener());
    

    When file will modified , create or get deleted it will call CustomFileListener.

    Following is the implementation of CustomFileListener.

    import org.apache.commons.vfs2.FileChangeEvent;
    import org.apache.commons.vfs2.FileListener;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.web.context.ContextLoader;
    import org.springframework.web.context.support.XmlWebApplicationContext;
    
    public class CustomFileListener implements FileListener {
    
    private static final Logger LOG = LoggerFactory.getLogger(CustomFileListener.class);
    
    @Override
    public void fileCreated(FileChangeEvent fileChangeEvent) throws Exception {
    
    }
    
    @Override
    public void fileDeleted(FileChangeEvent fileChangeEvent) throws Exception {
    
    }
    
    @Override
    public void fileChanged(FileChangeEvent fileChangeEvent) throws Exception {
    
    
        LOG.debug(" Under FileChanged Method");
        LOG.debug(" File has been changed hence reinitializing init method = " + fileChangeEvent.getFile().getName().getPath());
        XmlWebApplicationContext xmlWebApplicationContext =
                (XmlWebApplicationContext) ContextLoader.getCurrentWebApplicationContext();
        DefaultListableBeanFactory defaultListableBeanFactory =
                (DefaultListableBeanFactory) xmlWebApplicationContext.getBeanFactory();
        DroolsServiceImpl droolsService = (DroolsServiceImpl) defaultListableBeanFactory.getBean("droolsService");
        droolsService.init();
    }
    

    }

    What i did when the file will change, It will call fileChanged method.

    In that i have fetched cached bean(DroolServiceImpl) from ContextLoader.getCurrentWebApplicationContext(); and called its init() method.

    So this it will reload whole process and reinitialize the KieModule,KieRepository.