001/*
002 * #%L
003 * Netarchivesuite - heritrix 3 monitor
004 * %%
005 * Copyright (C) 2005 - 2018 The Royal Danish Library, 
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.heritrix3.monitor.resources;
025
026import java.io.File;
027import java.io.IOException;
028import java.net.URL;
029import java.text.NumberFormat;
030import java.util.List;
031import java.util.Locale;
032
033import javax.servlet.ServletContext;
034import javax.servlet.ServletOutputStream;
035import javax.servlet.http.HttpServletRequest;
036import javax.servlet.http.HttpServletResponse;
037
038import org.netarchivesuite.heritrix3wrapper.jaxb.Job;
039
040import com.antiaction.common.filter.Caching;
041import com.antiaction.common.templateengine.TemplateBuilderFactory;
042
043import dk.netarkivet.common.utils.Settings;
044import dk.netarkivet.harvester.HarvesterSettings;
045import dk.netarkivet.harvester.datamodel.HarvestDefinitionDAO;
046import dk.netarkivet.harvester.datamodel.JobStatus;
047import dk.netarkivet.heritrix3.monitor.Heritrix3JobMonitor;
048import dk.netarkivet.heritrix3.monitor.Heritrix3JobMonitorThread;
049import dk.netarkivet.heritrix3.monitor.NASEnvironment;
050import dk.netarkivet.heritrix3.monitor.NASUser;
051import dk.netarkivet.heritrix3.monitor.ResourceAbstract;
052import dk.netarkivet.heritrix3.monitor.ResourceManagerAbstract;
053import dk.netarkivet.heritrix3.monitor.HttpLocaleHandler.HttpLocale;
054
055public class H3JobResource implements ResourceAbstract {
056
057    private NASEnvironment environment;
058
059    protected int R_JOB = -1;
060
061    @Override
062    public void resources_init(NASEnvironment environment) {
063        this.environment = environment;
064    }
065
066    @Override
067    public void resources_add(ResourceManagerAbstract resourceManager) {
068        R_JOB = resourceManager.resource_add(this, "/job/<numeric>/", false);
069    }
070
071    @Override
072    public void resource_service(ServletContext servletContext, NASUser nas_user, HttpServletRequest req, HttpServletResponse resp, HttpLocale httpLocale, int resource_id, List<Integer> numerics, String pathInfo) throws IOException {
073        if (NASEnvironment.contextPath == null) {
074            NASEnvironment.contextPath = req.getContextPath();
075        }
076        if (NASEnvironment.servicePath == null) {
077            NASEnvironment.servicePath = req.getContextPath() + req.getServletPath() + "/";
078        }
079        String method = req.getMethod().toUpperCase();
080        if (resource_id == R_JOB) {
081            if ("GET".equals(method)) {
082                job(req, resp, httpLocale, numerics);
083            }
084        }
085    }
086
087    public void job(HttpServletRequest req, HttpServletResponse resp, HttpLocale httpLocale, List<Integer> numerics) throws IOException {
088        Locale locale = httpLocale.locale;
089        NumberFormat numberFormat = NumberFormat.getInstance(locale);
090        resp.setContentType("text/html; charset=UTF-8");
091        ServletOutputStream out = resp.getOutputStream();
092        Caching.caching_disable_headers(resp);
093
094        TemplateBuilderFactory<MasterTemplateBuilder> masterTplBuilderFactory = TemplateBuilderFactory.getInstance(environment.templateMaster, "master.tpl", "UTF-8", MasterTemplateBuilder.class);
095        MasterTemplateBuilder masterTplBuilder = masterTplBuilderFactory.getTemplateBuilder();
096
097        StringBuilder sb = new StringBuilder();
098
099        long jobId = numerics.get(0);
100        Heritrix3JobMonitor h3Job = environment.h3JobMonitorThread.getRunningH3Job(jobId);
101        Job job;
102        
103        HarvestDefinitionDAO dao = HarvestDefinitionDAO.getInstance();   
104
105        if (h3Job != null && !h3Job.bInitialized) {
106            h3Job.init();
107        }
108
109        dk.netarkivet.harvester.datamodel.Job nasJob = Heritrix3JobMonitorThread.jobDAO.read(jobId);
110
111        String action = req.getParameter("action");
112        if (action != null && action.length() > 0) {
113            if ("failed".equalsIgnoreCase(action)) {
114                if (nasJob != null && (h3Job == null || !h3Job.isReady())) {
115                        nasJob.setStatus(JobStatus.FAILED);
116                    Heritrix3JobMonitorThread.jobDAO.update(nasJob);
117                }
118            }
119        }
120
121        if (nasJob == null || nasJob.getStatus() == JobStatus.DONE || nasJob.getStatus() == JobStatus.FAILED || nasJob.getStatus() == JobStatus.FAILED_REJECTED) {
122            sb.append("NAS Job ");
123            sb.append(jobId);
124            sb.append(" is in state ");
125            sb.append(nasJob.getStatus().toString());
126            sb.append(".");
127        } else {
128            if (h3Job == null || !h3Job.isReady()) {
129                sb.append("Job ");
130                sb.append(jobId);
131                sb.append(" is not currently monitored. Maybe Heritrix 3 is not running at this point in time.");
132                if (nasJob != null && nasJob.getStatus() == JobStatus.STARTED && (h3Job == null || !h3Job.isReady())) {
133                    sb.append("<br />\n");
134                    sb.append("<a href=\"?action=");
135                    sb.append("failed");
136                    sb.append("\"");
137                        sb.append(" onclick=\"return confirm('Are you sure you wish to fail the job currently being crawled ?')\"");
138                    sb.append(" class=\"btn btn-danger\">");
139                    sb.append("<i class=\\\"icon-white icon-trash\\\"></i>");
140                    sb.append("Set job status to failed!");
141                    sb.append("</a>");
142                }
143            } else {
144                if (action != null && action.length() > 0) {
145                    if ("build".equalsIgnoreCase(action)) {
146                        h3Job.h3wrapper.buildJobConfiguration(h3Job.jobname);
147                    }
148                    if ("launch".equalsIgnoreCase(action)) {
149                        h3Job.h3wrapper.launchJob(h3Job.jobname);
150                    }
151                    if ("pause".equalsIgnoreCase(action)) {
152                        h3Job.h3wrapper.pauseJob(h3Job.jobname);
153                    }
154                    if ("unpause".equalsIgnoreCase(action)) {
155                        h3Job.h3wrapper.unpauseJob(h3Job.jobname);
156                    }
157                    if ("checkpoint".equalsIgnoreCase(action)) {
158                        h3Job.h3wrapper.checkpointJob(h3Job.jobname);
159                    }
160                    if ("terminate".equalsIgnoreCase(action)) {
161                        h3Job.h3wrapper.terminateJob(h3Job.jobname);
162                    }
163                    if ("teardown".equalsIgnoreCase(action)) {
164                        h3Job.h3wrapper.teardownJob(h3Job.jobname);
165                    }
166                }
167
168                //job.setStatus(JobStatus.FAILED);
169
170                h3Job.update();
171
172                sb.append("<div>\n");
173
174                sb.append("<div style=\"float:left;min-width: 300px;\">\n");
175
176                sb.append("JobId: <a href=\"/History/Harveststatus-jobdetails.jsp?jobID="+h3Job.jobId+"\">");
177                sb.append(h3Job.jobId);
178                sb.append("</a><br />\n");
179                if (h3Job.jobResult != null && h3Job.jobResult.job != null) {
180                        sb.append("JobState: ");
181                        sb.append(h3Job.jobResult.job.crawlControllerState);
182                        sb.append("<br />\n");
183                }
184                String harvestName = dao.getHarvestName(h3Job.job.getOrigHarvestDefinitionID());
185                sb.append("OrigHarvestDefinitionName: <a href=\"/HarvestDefinition/Definitions-edit-selective-harvest.jsp?harvestname="+harvestName.replace(' ', '+')+"\">");
186                sb.append(harvestName);
187                sb.append("</a><br />\n");
188                sb.append("HarvestNum: ");
189                sb.append(h3Job.job.getHarvestNum());
190                sb.append("<br />\n");
191                sb.append("Snapshot: ");
192                sb.append(h3Job.job.isSnapshot());
193                sb.append("<br />\n");
194                sb.append("Channel: ");
195                sb.append(h3Job.job.getChannel());
196                sb.append("<br />\n");
197                sb.append("TemplateName: <a href=\"");
198                sb.append("/History/Harveststatus-download-job-harvest-template.jsp?JobID=");
199                sb.append(h3Job.jobId);
200                sb.append("\">");
201                sb.append(h3Job.job.getOrderXMLName());
202                sb.append("</a><br />\n");
203                sb.append("CountDomains: ");
204                sb.append(h3Job.job.getCountDomains());
205                sb.append("<br />\n");
206                sb.append("MaxBytesPerDomain: ");
207                sb.append(numberFormat.format(h3Job.job.getMaxBytesPerDomain()));
208                sb.append("<br />\n");
209                sb.append("MaxObjectsPerDomain: ");
210                sb.append(numberFormat.format(h3Job.job.getMaxObjectsPerDomain()));
211                sb.append("<br />\n");
212                sb.append("MaxJobRunningTime: ");
213                sb.append(h3Job.job.getMaxJobRunningTime());
214                sb.append(" ms.<br />\n");
215                
216                sb.append("</div>\n");
217                
218                /* Heritrix3 WebUI */
219                sb.append("<div style=\"float:left;position: absolute;left:600px;\">\n");
220                sb.append("<a href=\"");
221                sb.append(h3Job.hostUrl);
222                sb.append("\" class=\"btn btn-default\">");
223                sb.append("Heritrix3 WebUI");
224                sb.append("</a>");
225                
226                sb.append("</div>\n");
227                
228                sb.append("<div style=\"clear:both;\"></div>");
229                sb.append("</div>");
230                
231                /* line 1 */
232                
233                sb.append("<h4>Job details</h4>\n");
234                sb.append("<div>\n");
235                
236                /* Progression/Queues */
237                sb.append("<a href=\"");
238                sb.append("/History/Harveststatus-running-jobdetails.jsp?jobID=");
239                sb.append(h3Job.jobId);
240                sb.append("\" class=\"btn btn-default\">");
241                sb.append("Progression/Queues");
242                sb.append("</a>");
243
244                sb.append("&nbsp;");
245                
246                /* Show Crawllog on H3 GUI*/
247                URL url1 = new URL(h3Job.hostUrl);
248                sb.append("<a href=\"");
249                sb.append("https://"+url1.getHost()+":"+url1.getPort()+"/engine/anypath/");
250                sb.append(h3Job.crawlLogFilePath);
251                sb.append("?format=paged&pos=-1&lines=-1000&reverse=y");
252                sb.append("\" class=\"btn btn-default\">");
253                sb.append("Remote H3 Crawllog viewer");
254                sb.append("</a>");
255                
256                sb.append("&nbsp;");
257
258                /* Crawllog */
259                sb.append("<a href=\"");
260                sb.append(NASEnvironment.servicePath);
261                sb.append("job/");
262                sb.append(h3Job.jobId);
263                sb.append("/crawllog/");
264                sb.append("\" class=\"btn btn-default\">");
265                sb.append("View/Search in cached Crawllog");
266                sb.append("</a>");
267
268                sb.append("&nbsp;");
269                
270                /* Reports */
271                sb.append("<a href=\"");
272                sb.append(NASEnvironment.servicePath);
273                sb.append("job/");
274                sb.append(h3Job.jobId);
275                sb.append("/report/");
276                sb.append("\" class=\"btn btn-default\">");
277                sb.append("Reports");
278                sb.append("</a>");
279
280                sb.append("&nbsp;");
281
282                sb.append("</div>\n");
283                
284                /* line 2 */
285                
286                sb.append("<h4>Queue actions</h4>\n");
287                sb.append("<div>\n");
288                
289                /* Show/delete Frontier */
290                sb.append("<a href=\"");
291                sb.append(NASEnvironment.servicePath);
292                sb.append("job/");
293                sb.append(h3Job.jobId);
294                sb.append("/frontier/");
295                sb.append("\" class=\"btn btn-default\">");
296                sb.append("Browse/delete Frontier");
297                sb.append("</a>");
298
299                sb.append("&nbsp;");
300                
301                /* Delete from Frontier */
302                sb.append("<a href=\"");
303                sb.append(NASEnvironment.servicePath);
304                sb.append("job/");
305                sb.append(h3Job.jobId);
306                sb.append("/frontier-delete/");
307                sb.append("\" class=\"btn btn-default\">");
308                sb.append("Delete from Frontier");
309                sb.append("</a>");
310
311                sb.append("&nbsp;");
312                
313                /* Add RejectRules */
314                sb.append("<a href=\"");
315                sb.append(NASEnvironment.servicePath);
316                sb.append("job/");
317                sb.append(h3Job.jobId);
318                sb.append("/filter/");
319                sb.append("\" class=\"btn btn-default\">");
320                sb.append("Add RejectRules");
321                sb.append("</a>");
322
323                sb.append("&nbsp;");
324                
325                /* Modify Budget */
326                sb.append("<a href=\"");
327                sb.append(NASEnvironment.servicePath);
328                sb.append("job/");
329                sb.append(h3Job.jobId);
330                sb.append("/budget/");
331                sb.append("\" class=\"btn btn-default\">");
332                sb.append("Modify budget");
333                sb.append("</a>");
334
335                sb.append("&nbsp;");
336                
337                sb.append("</div>\n");
338
339                if (h3Job.jobResult != null && h3Job.jobResult.job != null) {
340                        
341                        /* line 3 */
342                    
343                    sb.append("<h4>Job actions</h4>\n");
344                    sb.append("<div style=\"margin-bottom:30px;\">\n");
345                        
346                    job = h3Job.jobResult.job;
347
348                    for (int i=0; i<job.availableActions.size(); ++i) {
349                        if (i > 0) {
350                            sb.append("&nbsp;");
351                        }
352                        //  disabled="disabled"
353                        sb.append("<a href=\"?action=");
354                        String thisAction = job.availableActions.get(i);
355                        sb.append(thisAction);
356                        sb.append("\"");
357                        if("terminate".equals(thisAction) || "teardown".equals(thisAction)) {
358                                sb.append(" onclick=\"return confirm('Are you sure you wish to ");
359                                sb.append(thisAction);
360                                sb.append(" the job currently being crawled ?')\"");
361                            sb.append(" class=\"btn btn-danger\">");
362                            sb.append("<i class=\\\"icon-white icon-trash\\\"></i>");
363                        } else {
364                            sb.append(" class=\"btn btn-default\">");
365                        }
366                        sb.append(job.availableActions.get(i).substring(0, 1).toUpperCase()+job.availableActions.get(i).substring(1));
367                        sb.append("</a>");
368                    }
369                    
370                    sb.append("&nbsp;");
371                    
372                    /* Open Scripting Console */
373                    sb.append("<a href=\"");
374                    sb.append(NASEnvironment.servicePath);
375                    sb.append("job/");
376                    sb.append(h3Job.jobId);
377                    sb.append("/script/");
378                    sb.append("\" class=\"btn btn-default\">");
379                    sb.append("Open Scripting Console");
380                    sb.append("</a>");
381
382                    sb.append("&nbsp;");
383                    
384                    /* View scripting_events.log */
385                    File logDir = new File(h3Job.crawlLogFilePath);
386                    
387                    sb.append("<a href=\"");
388                    URL url = new URL(h3Job.hostUrl);
389                    sb.append("https://"+url.getHost()+":"+url.getPort()+"/engine/anypath"+logDir.getParentFile().getAbsolutePath()+"/scripting_events.log");
390                    sb.append("\" class=\"btn btn-default\">");
391                    sb.append("View scripting_events.log");
392                    sb.append("</a>");
393                    
394                    sb.append("</div>\n");
395
396                    sb.append("shortName: ");
397                    sb.append(job.shortName);
398                    sb.append("<br />\n");
399                    sb.append("crawlControllerState: ");
400                    sb.append(job.crawlControllerState);
401                    sb.append("<br />\n");
402                    sb.append("crawlExitStatus: ");
403                    sb.append(job.crawlExitStatus);
404                    sb.append("<br />\n");
405                    sb.append("statusDescription: ");
406                    sb.append(job.statusDescription);
407                    sb.append("<br />\n");
408                    sb.append("url: ");
409                    sb.append("<a href=\"");
410                    sb.append(h3Job.hostUrl+"/job/"+h3Job.jobname);
411                    sb.append("/");
412                    sb.append("\">");
413                    sb.append(h3Job.hostUrl+"/job/"+h3Job.jobname);
414                    sb.append("</a>");
415                    sb.append("<br />\n");
416                    if (job.jobLogTail != null) {
417                        for (int i =0; i<job.jobLogTail.size(); ++i) {
418                            sb.append("jobLogTail[");
419                            sb.append(i);
420                            sb.append("]: ");
421                            sb.append(job.jobLogTail.get(i));
422                            sb.append("<br />\n");
423                        }
424                    }
425                    if (job.uriTotalsReport != null) {
426                        sb.append("uriTotalsReport.downloadedUriCount: ");
427                        sb.append(job.uriTotalsReport.downloadedUriCount);
428                        sb.append("<br />\n");
429                        sb.append("uriTotalsReport.queuedUriCount: ");
430                        sb.append(job.uriTotalsReport.queuedUriCount);
431                        sb.append("<br />\n");
432                        sb.append("uriTotalsReport.totalUriCount: ");
433                        sb.append(job.uriTotalsReport.totalUriCount);
434                        sb.append("<br />\n");
435                        sb.append("uriTotalsReport.futureUriCount: ");
436                        sb.append(job.uriTotalsReport.futureUriCount);
437                        sb.append("<br />\n");
438                    }
439                    if (job.sizeTotalsReport != null) {
440                        sb.append("sizeTotalsReport.dupByHash: ");
441                        sb.append(job.sizeTotalsReport.dupByHash);
442                        sb.append("<br />\n");
443                        sb.append("sizeTotalsReport.dupByHashCount: ");
444                        sb.append(job.sizeTotalsReport.dupByHashCount);
445                        sb.append("<br />\n");
446                        sb.append("sizeTotalsReport.novel: ");
447                        sb.append(job.sizeTotalsReport.novel);
448                        sb.append("<br />\n");
449                        sb.append("sizeTotalsReport.novelCount: ");
450                        sb.append(job.sizeTotalsReport.novelCount);
451                        sb.append("<br />\n");
452                        sb.append("sizeTotalsReport.notModified: ");
453                        sb.append(job.sizeTotalsReport.notModified);
454                        sb.append("<br />\n");
455                        sb.append("sizeTotalsReport.notModifiedCount: ");
456                        sb.append(job.sizeTotalsReport.notModifiedCount);
457                        sb.append("<br />\n");
458                        sb.append("sizeTotalsReport.total: ");
459                        sb.append(job.sizeTotalsReport.total);
460                        sb.append("<br />\n");
461                        sb.append("sizeTotalsReport.totalCount: ");
462                        sb.append(job.sizeTotalsReport.totalCount);
463                        sb.append("<br />\n");
464                    }
465                    if (job.rateReport != null) {
466                        sb.append("rateReport.currentDocsPerSecond: ");
467                        sb.append(job.rateReport.currentDocsPerSecond);
468                        sb.append("<br />\n");
469                        sb.append("rateReport.averageDocsPerSecond: ");
470                        sb.append(job.rateReport.averageDocsPerSecond);
471                        sb.append("<br />\n");
472                        sb.append("rateReport.currentKiBPerSec: ");
473                        sb.append(job.rateReport.currentKiBPerSec);
474                        sb.append("<br />\n");
475                        sb.append("rateReport.averageKiBPerSec: ");
476                        sb.append(job.rateReport.averageKiBPerSec);
477                        sb.append("<br />\n");
478                    }
479                    if (job.loadReport != null) {
480                        sb.append("loadReport.busyThreads: ");
481                        sb.append(job.loadReport.busyThreads);
482                        sb.append("<br />\n");
483                        sb.append("loadReport.totalThreads: ");
484                        sb.append(job.loadReport.totalThreads);
485                        sb.append("<br />\n");
486                        sb.append("loadReport.congestionRatio: ");
487                        sb.append(job.loadReport.congestionRatio);
488                        sb.append("<br />\n");
489                        sb.append("loadReport.averageQueueDepth: ");
490                        sb.append(job.loadReport.averageQueueDepth);
491                        sb.append("<br />\n");
492                        sb.append("loadReport.deepestQueueDepth: ");
493                        sb.append(job.loadReport.deepestQueueDepth);
494                        sb.append("<br />\n");
495                    }
496                    if (job.elapsedReport != null) {
497                        sb.append("elapsedReport.elapsed: ");
498                        sb.append(job.elapsedReport.elapsedPretty);
499                        sb.append(" (");
500                        sb.append(job.elapsedReport.elapsedMilliseconds);
501                        sb.append("ms)");
502                        sb.append("<br />\n");
503                    }
504                    if (job.threadReport != null) {
505                        sb.append("threadReport.toeCount: ");
506                        sb.append(job.threadReport.toeCount);
507                        sb.append("<br />\n");
508                        if (job.threadReport.steps != null) {
509                            for (int i =0; i<job.threadReport.steps.size(); ++i) {
510                                sb.append("threadReport.steps[");
511                                sb.append(i);
512                                sb.append("]: ");
513                                sb.append(job.threadReport.steps.get(i));
514                                sb.append("<br />\n");
515                            }
516                        }
517                        if (job.threadReport.processors != null) {
518                            for (int i =0; i<job.threadReport.processors.size(); ++i) {
519                                sb.append("threadReport.processors[");
520                                sb.append(i);
521                                sb.append("]: ");
522                                sb.append(job.threadReport.processors.get(i));
523                                sb.append("<br />\n");
524                            }
525                        }
526                    }
527                    if (job.frontierReport != null) {
528                        sb.append("frontierReport.totalQueues: ");
529                        sb.append(job.frontierReport.totalQueues);
530                        sb.append("<br />\n");
531                        sb.append("frontierReport.inProcessQueues: ");
532                        sb.append(job.frontierReport.inProcessQueues);
533                        sb.append("<br />\n");
534                        sb.append("frontierReport.readyQueues: ");
535                        sb.append(job.frontierReport.readyQueues);
536                        sb.append("<br />\n");
537                        sb.append("frontierReport.snoozedQueues: ");
538                        sb.append(job.frontierReport.snoozedQueues);
539                        sb.append("<br />\n");
540                        sb.append("frontierReport.activeQueues: ");
541                        sb.append(job.frontierReport.activeQueues);
542                        sb.append("<br />\n");
543                        sb.append("frontierReport.inactiveQueues: ");
544                        sb.append(job.frontierReport.inactiveQueues);
545                        sb.append("<br />\n");
546                        sb.append("frontierReport.ineligibleQueues: ");
547                        sb.append(job.frontierReport.ineligibleQueues);
548                        sb.append("<br />\n");
549                        sb.append("frontierReport.retiredQueues: ");
550                        sb.append(job.frontierReport.retiredQueues);
551                        sb.append("<br />\n");
552                        sb.append("frontierReport.exhaustedQueues: ");
553                        sb.append(job.frontierReport.exhaustedQueues);
554                        sb.append("<br />\n");
555                        sb.append("frontierReport.lastReachedState: ");
556                        sb.append(job.frontierReport.lastReachedState);
557                        sb.append("<br />\n");
558                    }
559                    if (job.crawlLogTail != null) {
560                        for (int i =0; i<job.crawlLogTail.size(); ++i) {
561                            sb.append("crawlLogTail[");
562                            sb.append(i);
563                            sb.append("]: ");
564                            sb.append(job.crawlLogTail.get(i));
565                            sb.append("<br />\n");
566                        }
567                    }
568                    sb.append("isRunning: ");
569                    sb.append(job.isRunning);
570                    sb.append("<br />\n");
571                    sb.append("isLaunchable: ");
572                    sb.append(job.isLaunchable);
573                    sb.append("<br />\n");
574                    sb.append("alertCount: ");
575                    sb.append(job.alertCount);
576                    sb.append("<br />\n");
577                    sb.append("alertLogFilePath: ");
578                    sb.append(job.alertLogFilePath);
579                    sb.append("<br />\n");
580                    sb.append("crawlLogFilePath: ");
581                    sb.append(job.crawlLogFilePath);
582                    sb.append("<br />\n");
583                    if (job.heapReport != null) {
584                        sb.append("heapReport.usedBytes: ");
585                        sb.append(job.heapReport.usedBytes);
586                        sb.append("<br />\n");
587                        sb.append("heapReport.totalBytes: ");
588                        sb.append(job.heapReport.totalBytes);
589                        sb.append("<br />\n");
590                        sb.append("heapReport.maxBytes: ");
591                        sb.append(job.heapReport.maxBytes);
592                        sb.append("<br />\n");
593                    }
594                }
595            }
596        }
597
598        StringBuilder menuSb = masterTplBuilder.buildMenu(new StringBuilder(), req, locale, h3Job);
599
600        masterTplBuilder.insertContent("Details and Actions on Running Job " + jobId, menuSb.toString(), httpLocale.generateLanguageLinks(),
601                        "Details and Actions on Running Job " + jobId, sb.toString(),
602                "<link rel=\"shortcut icon\" type=\"image/png\" href=\"/transparent_menu_logo.png\"/>"
603                        +
604                        "<meta http-equiv=\"refresh\" content=\""+Settings.get(HarvesterSettings.HARVEST_MONITOR_REFRESH_INTERVAL)+"\"/>\n").write(out);
605
606        out.flush();
607        out.close();
608    }
609
610}