001package com.thed.zblast.scheduler;
002
003import com.thed.model.AutomationJobDetail;
004import com.thed.model.AutomationJobScheduleDTO;
005import com.thed.zblast.util.RestUtil;
006import org.apache.commons.io.FilenameUtils;
007import org.apache.commons.io.monitor.FileAlterationListener;
008import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
009import org.apache.commons.io.monitor.FileAlterationMonitor;
010import org.apache.commons.io.monitor.FileAlterationObserver;
011import org.w3c.dom.Document;
012import org.w3c.dom.Element;
013import org.w3c.dom.Node;
014import org.w3c.dom.NodeList;
015import org.xml.sax.SAXException;
016
017import javax.xml.parsers.DocumentBuilder;
018import javax.xml.parsers.DocumentBuilderFactory;
019import javax.xml.parsers.ParserConfigurationException;
020import javax.xml.xpath.XPath;
021import javax.xml.xpath.XPathConstants;
022import javax.xml.xpath.XPathExpressionException;
023import javax.xml.xpath.XPathFactory;
024import java.io.File;
025import java.io.IOException;
026import java.util.*;
027
028public class ScheduledJobExecutor {
029
030        private static final int POLL_INTERVAL = 500;
031        
032         public static Integer getAutomationJobResultFilereadingMonitorWaitTime() {
033                 
034                 return RestUtil.getAutomationJobResultFilereadingMonitorWaitTime();
035         }
036
037        private Map<String, Map<String, Integer>> jobExecutionCounterMap = new HashMap<>();
038        
039        ////to track last file read time for this job
040        private Map<String, java.util.Date> jobExecutionLastFileReadTimer = new HashMap<>();
041
042        public void executeJob(AutomationJobDetail automationJobDetail) {
043
044                List<AutomationJobScheduleDTO> automationJobScheduleDTOs;
045                try {
046
047                        automationJobScheduleDTOs = RestUtil.createScheduleForSchduledJobs(automationJobDetail, "initialized");
048                        // not only status also update cycle and phase name with timestamp...
049
050                        System.out.println("automationJobScheduleDTOs:::" + automationJobScheduleDTOs);
051                        if (automationJobScheduleDTOs != null && !automationJobScheduleDTOs.isEmpty()) {
052
053                                AutomationJobScheduleDTO dto = automationJobScheduleDTOs.get(0);
054
055                                automationJobDetail.setScheduleId(dto.getId());
056
057                                System.out.println("automationJobDetail >>> " + automationJobDetail.getScheduleId());
058
059                        }
060
061                        System.out.println("automationJobDetail:: " + automationJobDetail);
062
063                        System.out.println("automationJobDetail.getScriptPath()::" + automationJobDetail.getScriptPath());
064                        jobExecutionCounterMap.put(automationJobDetail.getJobName(), new HashMap<>());
065
066                        System.out.println(Thread.currentThread().getName() + " 123| Kicking off the process...");
067
068                        StringBuilder command = new StringBuilder(automationJobDetail.getScriptPath());
069                        final Process process = Runtime.getRuntime().exec(command.toString());
070                        
071                        this.startListener(automationJobDetail);
072                        
073                        int returnCode = process.waitFor();
074                        System.out.println("returnCode::::::::"+returnCode);
075                        if (returnCode == 0) {
076                                // pass
077                                System.out.println("Pass..");
078                                
079                                //start file reader listener..
080                                
081                        }else {
082                                
083                                //update zee for job failed..
084                                System.out.println("Failed script for job");
085                                
086                                RestUtil.updateZblastScheduleStatus(automationJobDetail.getScheduleId(), "job_failed_failed_to_execute_command",null, automationJobDetail);
087                                
088                        }
089
090                } catch (IOException e) {
091                        e.printStackTrace();
092                } catch (InterruptedException e) {
093                        e.printStackTrace();
094                } catch (Exception e) {
095                        e.printStackTrace();
096                }
097
098        }
099        
100        
101        
102        private void startListener(AutomationJobDetail automationJobDetail) throws Exception {
103                ScheduledJobExecutor scheduledJobExecutor = new ScheduledJobExecutor();
104                
105                FileAlterationObserver observer = new FileAlterationObserver( automationJobDetail.getResultPath());
106
107                FileAlterationMonitor monitor = new FileAlterationMonitor(POLL_INTERVAL);
108                FileAlterationListener listener = new FileAlterationListenerAdaptor() {
109                        @Override
110                        public void onFileCreate(File file) {
111                                System.out.println("""
112                                                File: %s created""".formatted(file.getName()));
113                                //to track last file read time for this job
114                                
115                                String ext = FilenameUtils.getExtension(file.getName());
116                                
117                                System.out.println("ext:::"+ext);
118                                
119                                if(ext.equalsIgnoreCase("xml"))
120                                {
121                                        System.out.println("Inside xml file +"+file.getName());
122                                        JobProgressDTO  jobProgressDTO = getProgressResultFromFile(file);
123                                        scheduledJobExecutor.postProgressDetails(automationJobDetail,jobProgressDTO);
124                                        jobExecutionLastFileReadTimer.put(automationJobDetail.getJobName(), new java.util.Date());
125                                }
126                        }
127
128                        @Override
129                        public void onFileDelete(File file) {
130                                System.out.println("""
131                                                File: %s deleted""".formatted(file.getName()));
132                        }
133
134                        @Override
135                        public void onFileChange(File file) {
136                                System.out.println("""
137                                                File: %s changed""".formatted(file.getName()));
138                        }
139                };
140                observer.addListener(listener);
141                monitor.addObserver(observer);
142                monitor.start();
143
144                //monitor and stop the job after certain interval
145                Timer time = new Timer(); // Instantiate Timer Object
146                ScheduledTask st = new ScheduledTask(monitor, automationJobDetail); // Instantiate SheduledTask class
147                time.schedule(st, 0, 60000); // Create Repetitively task for every 30 secs
148
149                
150        }
151        
152        //Scheduler to check and kill the monitoring of file after last file read interval
153        public class ScheduledTask extends TimerTask {
154
155                Date now; // to display current time
156                FileAlterationMonitor monitor = null;
157                AutomationJobDetail automationJobDetail = null;
158                
159                ScheduledTask(FileAlterationMonitor monitor, AutomationJobDetail automationJobDetail){
160                        
161                        this.monitor = monitor;
162                        this.automationJobDetail =  automationJobDetail;
163                }
164
165                
166                public void run() {
167                        now = new Date(); // initialize date
168                        System.out.println("Time is :" + now); // Display current time
169                        Date lastReadTime = jobExecutionLastFileReadTimer.get(automationJobDetail.getJobName());
170                        
171                        if(lastReadTime == null) {
172                                lastReadTime = new Date();
173                        }
174                        
175                        long diff = new Date().getTime() - lastReadTime.getTime();
176
177                        long minutes =  diff / (60 * 1000) % 60;
178                        
179                        System.out.println("minutes diff::"+minutes);
180                        
181                        if( minutes > getAutomationJobResultFilereadingMonitorWaitTime()) { // stop the job after last file read -- wait for configured time.
182                                
183                                try {
184                                        System.out.println("Stoping the job:"+automationJobDetail);
185                                        monitor.stop();
186                                        //cleanup tasks..
187                                        jobExecutionCounterMap.put(automationJobDetail.getJobName(), null);
188                                        
189                                        //set job to new so that result processor picks the job
190                                        RestUtil.updateZblastScheduleStatus(automationJobDetail.getScheduleId(), "new", null, automationJobDetail);
191                                        
192                                        this.cancel();
193
194                                } catch (Exception e) {
195                                        e.printStackTrace();
196                                }
197                        }
198                        
199                }
200        }
201
202        private JobProgressDTO getProgressResultFromFile(File resultFile) {
203
204                JobProgressDTO progressDTO = new JobProgressDTO();
205
206                try {
207                        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
208                        DocumentBuilder dBuilder;
209
210                        dBuilder = dbFactory.newDocumentBuilder();
211
212                        Document doc = dBuilder.parse(resultFile);
213                        doc.getDocumentElement().normalize();
214
215                        XPath xPath = XPathFactory.newInstance().newXPath();
216
217                        String expression = "testsuite";
218                        NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET);
219
220                        for (int i = 0; i < nodeList.getLength(); i++) {
221                                Node nNode = nodeList.item(i);
222                                System.out.println("\nCurrent Element :" + nNode.getNodeName());
223
224                                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
225                                        Element eElement = (Element) nNode;
226                                        System.out.println("tests :" + eElement.getAttribute("tests"));
227                                        System.out.println("failures :" + eElement.getAttribute("failures"));
228                                        System.out.println("errors :" + eElement.getAttribute("errors"));
229                                        System.out.println("skipped :" + eElement.getAttribute("skipped"));
230
231                                        progressDTO.setErrorCount(Integer.valueOf(eElement.getAttribute("errors").trim()).intValue());
232                                        progressDTO.setExecutedCount(Integer.valueOf(eElement.getAttribute("tests").trim()).intValue());
233                                        progressDTO.setFailedCount(Integer.valueOf(eElement.getAttribute("failures").trim()).intValue());
234                                        progressDTO.setSkippedCount(Integer.valueOf(eElement.getAttribute("skipped").trim()).intValue());
235
236                                }
237                        }
238                } catch (ParserConfigurationException e) {
239                        e.printStackTrace();
240                } catch (SAXException e) {
241                        e.printStackTrace();
242                } catch (IOException e) {
243                        e.printStackTrace();
244                } catch (XPathExpressionException e) {
245                        e.printStackTrace();
246                }
247                System.out.println("Before returning progressDTO::"+progressDTO);
248                return progressDTO;
249
250        }
251        
252
253        public void postProgressDetails(AutomationJobDetail automationJobDetail, JobProgressDTO jobProgressDTO)  {
254
255                try {
256                        
257                        System.out.println("In postProgressDetails jobProgressDTO::"+jobProgressDTO);
258                
259                Map<String, Integer> thisJobExecutionCounterMap = jobExecutionCounterMap.get(automationJobDetail.getJobName());
260                
261                System.out.println("thisJobExecutionCounterMap::::"+thisJobExecutionCounterMap);
262                
263                if(thisJobExecutionCounterMap == null) {
264                        
265                        thisJobExecutionCounterMap = new HashMap<>();
266                }
267                
268                if (thisJobExecutionCounterMap.containsKey("tests")) {
269                        thisJobExecutionCounterMap.put("tests", thisJobExecutionCounterMap.get("tests")+jobProgressDTO.getExecutedCount());
270                } else {
271                        thisJobExecutionCounterMap.put("tests", jobProgressDTO.getExecutedCount());
272                        
273                }
274                if (thisJobExecutionCounterMap.containsKey("failures")) {
275                        thisJobExecutionCounterMap.put("failures", thisJobExecutionCounterMap.get("failures")+jobProgressDTO.getFailedCount());
276                } else {
277                        thisJobExecutionCounterMap.put("failures", jobProgressDTO.getFailedCount());
278                        
279                }
280                
281                if (thisJobExecutionCounterMap.containsKey("skipped")) {
282                        thisJobExecutionCounterMap.put("skipped", thisJobExecutionCounterMap.get("skipped")+jobProgressDTO.getSkippedCount());
283                } else {
284                        thisJobExecutionCounterMap.put("skipped", jobProgressDTO.getSkippedCount());
285                        
286                }
287                
288                if (thisJobExecutionCounterMap.containsKey("errors")) {
289                        thisJobExecutionCounterMap.put("errors", thisJobExecutionCounterMap.get("errors")+jobProgressDTO.getErrorCount());
290                } else {
291                        thisJobExecutionCounterMap.put("errors", jobProgressDTO.getErrorCount());
292                        
293                }
294                
295                System.out.println("thisJobExecutionCounterMap :::"+thisJobExecutionCounterMap);
296                
297                
298                jobExecutionCounterMap.put(automationJobDetail.getJobName(), thisJobExecutionCounterMap);
299                
300                JobProgressDTO dto = new JobProgressDTO();
301
302                dto.setErrorCount(thisJobExecutionCounterMap.get("errors"));
303                dto.setExecutedCount(thisJobExecutionCounterMap.get("tests"));
304                dto.setFailedCount(thisJobExecutionCounterMap.get("failures"));
305                dto.setSkippedCount(thisJobExecutionCounterMap.get("skipped"));
306                dto.setJobName(automationJobDetail.getJobName());
307                dto.setSchedulerId(automationJobDetail.getScheduleId());
308
309                System.out.println("postProgressDetails ::: " + dto);
310
311                
312                        RestUtil.postProgressDetails(dto);
313                } catch (IOException e) {
314                        e.printStackTrace();
315                }
316        }
317
318        /**
319         * if (testExecutionCounterMap.containsKey(key)) {
320         * testExecutionCounterMap.put(key, testExecutionCounterMap.get(key) + (new
321         * Integer(value))); } else { testExecutionCounterMap.put(key, new
322         * Integer(value)); }
323         */
324
325}