001package dk.netarkivet.harvester.webinterface;
002
003import java.io.IOException;
004import java.util.Locale;
005import java.util.Map;
006
007import javax.servlet.http.HttpServletResponse;
008import javax.servlet.jsp.JspWriter;
009import javax.servlet.jsp.PageContext;
010
011import dk.netarkivet.common.exceptions.ArgumentNotValid;
012import dk.netarkivet.common.exceptions.ForwardedToErrorPage;
013import dk.netarkivet.common.exceptions.UnknownID;
014import dk.netarkivet.common.utils.I18n;
015import dk.netarkivet.common.utils.StringUtils;
016import dk.netarkivet.common.webinterface.HTMLUtils;
017import dk.netarkivet.common.webinterface.SiteSection;
018import dk.netarkivet.harvester.datamodel.DomainDAO;
019import dk.netarkivet.harvester.datamodel.HarvestDefinitionDAO;
020import dk.netarkivet.harvester.datamodel.HarvestInfo;
021import dk.netarkivet.harvester.datamodel.Job;
022import dk.netarkivet.harvester.datamodel.JobDAO;
023import dk.netarkivet.harvester.datamodel.JobStatus;
024
025/**
026 * Created by jve on 5/31/16.
027 */
028public class HarvestStatusJobDetails {
029    /** The job id for job the extracted from query parameter. */
030    private long jobID;
031    /** The job for the current page. */
032    private Job job;
033    /** Name of the havest. */
034    private String harvestname;
035    /** Url of the havest. */
036    private String harvesturl;
037    /** Url to job details. */
038    private String jobdetailsUrl;
039    /** Havest name for td content. */
040    private String harvestnameTdContents;
041    /** Job status td content. */
042    private String jobstatusTdContents;
043    /** Indicate weather definition sitesection is deployed. */
044    private boolean definitionsSitesectionDeployed;
045    /** Id of the havest */
046    private Long harvestID;
047
048    /**
049     * Constuctor for jsp Harveststatus-jobdetails.jsp. Initializes the objects needed to build the page. Code has been moved from the jsp to here to avoid compile errors at
050     * runtime in correlation with the upgrade to java 1.8 and introduction of embedded tomcat to handle jsp pages. This was previously done via jetty 6
051     *
052     * @param response http response to servlet request
053     * @param pageContext context object from jsp
054     * @param I18N the internationlization object from the jsp caller
055     */
056    public HarvestStatusJobDetails(HttpServletResponse response, PageContext pageContext, I18n I18N)
057            throws ArgumentNotValid {
058        ArgumentNotValid.checkNotNull(response, "ServletRequest response");
059        ArgumentNotValid.checkNotNull(pageContext, "PageContext pageContext");
060        ArgumentNotValid.checkNotNull(I18N, "I18n I18N");
061
062        try {
063            jobID = HTMLUtils.parseAndCheckInteger(pageContext, Constants.JOB_PARAM, 1, Integer.MAX_VALUE);
064        } catch (ForwardedToErrorPage e) {
065            return;
066        }
067
068        try {
069            job = JobDAO.getInstance().read(jobID);
070        } catch (UnknownID e) {
071            HTMLUtils.forwardWithErrorMessage(pageContext, I18N, "errormsg;job.unknown.id.0", jobID);
072            return;
073        }
074
075        harvesturl= "/HarvestDefinition/Definitions-selective-harvests.jsp";
076        jobdetailsUrl = "/History/Harveststatus-jobdetails.jsp";
077        definitionsSitesectionDeployed = SiteSection.isDeployed(Constants.DEFINITIONS_SITESECTION_DIRNAME);
078        harvestID = job.getOrigHarvestDefinitionID();
079        try {
080            harvestname = HarvestDefinitionDAO.getInstance().getHarvestName(harvestID);
081            // define harvesturl, only if we have deployed the Definitions sitesection
082            if (definitionsSitesectionDeployed) {
083                if (HarvestDefinitionDAO.getInstance().isSnapshot(harvestID)) {
084                    harvesturl =
085                            "/HarvestDefinition/Definitions-edit-snapshot-harvest.jsp?"
086                                    + Constants.HARVEST_PARAM + "="
087                                    + HTMLUtils.encode(harvestname);
088                } else {
089                    harvesturl = "/HarvestDefinition/Definitions-edit-selective-harvest.jsp?"
090                            + Constants.HARVEST_PARAM + "="
091                            + HTMLUtils.encode(harvestname);
092                }
093            }
094        } catch (UnknownID e) {
095            // If no harvestdefinition is known with ID=harvestID
096            // Set harvestname = an internationalized version of
097            // "Unknown harvest" + harvestID
098            harvestname = I18N.getString(response.getLocale(), "unknown.harvest.0", harvestID);
099        }
100        harvestnameTdContents = HTMLUtils.escapeHtmlValues(harvestname);
101        if (definitionsSitesectionDeployed) {
102            harvestnameTdContents = "<a href=\"" + HTMLUtils.escapeHtmlValues(harvesturl)
103                    + "\">" + HTMLUtils.escapeHtmlValues(harvestname) + "</a>";
104        }
105        jobstatusTdContents = job.getStatus().getLocalizedString(response.getLocale());
106        // If the status of the job is RESUBMITTED (and the new job is known),
107        // add a link to the new job
108        // Note: this information was only available from release 3.8.0
109        // So for historical jobs generated with previous versions of NetarchiveSuite,
110        // this information is not available.
111        if (job.getStatus().equals(JobStatus.RESUBMITTED)
112                && job.getResubmittedAsJob() != null) {
113            jobstatusTdContents += "<br/>(<a href=\"" + jobdetailsUrl + "?"
114                    + Constants.JOB_PARAM + "=" + job.getResubmittedAsJob() + "\">"
115                    + "Job " + job.getResubmittedAsJob() + "</a>" + ")";
116        }
117    }
118
119    public void PrintPageContent(JspWriter out, I18n I18N, Locale locale) throws IOException, ArgumentNotValid {
120        ArgumentNotValid.checkNotNull(out, "JspWriter out");
121        ArgumentNotValid.checkNotNull(I18N, "I18n I18N");
122        ArgumentNotValid.checkNotNull(locale, "Locale locale");
123
124        //Job details table
125        out.println("<h3 class=\"page_heading\">" + I18N.getString(locale, "pagetitle;details.for.job.0", jobID) + "</h3>");
126        out.println("<table class=\"selection_table\">");
127        out.println("<tr>");
128        out.println("<th>" + I18N.getString(locale, "table.job.jobid") + "</th>");
129        out.println("<th>" + I18N.getString(locale, "table.job.type") + "</th>");
130        out.println("<th>" + I18N.getString(locale, "table.job.harvestname") + "</th>");
131        out.println("<th>" + I18N.getString(locale, "table.job.harvestnumber") + "</th>");
132        out.println("<th>" + I18N.getString(locale, "table.job.creationtime") + "</th>");
133        out.println("<th>" + I18N.getString(locale, "table.job.starttime") + "</th>");
134        out.println("<th>" + I18N.getString(locale, "table.job.stoptime") + "</th>");
135        out.println("<th>" + I18N.getString(locale, "table.job.jobstatus") + "</th>");
136        out.println("<th>" + I18N.getString(locale, "table.job.harvesterror") + "</th>");
137        out.println("<th>" + I18N.getString(locale, "table.job.uploaderror") + "</th>");
138        out.println("<th>" + I18N.getString(locale, "table.job.objectlimit") + "</th>");
139        out.println("<th>" + I18N.getString(locale, "table.job.bytelimit") + "</th>");
140        out.println("</tr>");
141        out.println("<tr>");
142        out.println("<td>" + job.getJobID() + "</td>");
143        out.println("<td>" + job.getChannel() + "</td>");
144        out.println("<td>" + harvestnameTdContents + "</td>");
145        out.println("<td>" + dk.netarkivet.harvester.webinterface.HarvestStatus.makeHarvestRunLink(harvestID, job.getHarvestNum()) + "</td>");
146        out.println("<td>" + HTMLUtils.parseDate(job.getCreationDate()) + "</td>");
147        out.println("<td>" + HTMLUtils.parseDate(job.getActualStart()) + "</td>");
148        out.println("<td>" + HTMLUtils.parseDate(job.getActualStop()) + "</td>");
149        out.println("<td>" + jobstatusTdContents + "</td>");
150        out.println("<td><a href=\"#harvesterror\">" + HTMLUtils.escapeHtmlValues(job.getHarvestErrors()) + "</a></td>");
151        out.println("<td><a href=\"#uploaderror\">" + HTMLUtils.escapeHtmlValues(job.getUploadErrors()) + "</a></td>");
152        out.println("<td>" + job.getMaxObjectsPerDomain() + "</td>");
153        out.println("<td>" + job.getMaxBytesPerDomain() + "</td>");
154        out.println("</tr>");
155        out.println("</table>");
156        //display the searchFilter if QA webpages are deployed--
157
158        if (SiteSection.isDeployed(Constants.QA_SITESECTION_DIRNAME)) {
159            out.println("<h3>" + I18N.getString(locale, "subtitle.job.qa.selection") + "</h3>");
160            out.println("<table class=\"selection_table\"><tr><td>");
161            out.println("<p><a href=\"/" + Constants.QA_SITESECTION_DIRNAME + "/QA-changeIndex.jsp?" + Constants.JOB_PARAM + "=" +
162            job.getJobID() + "&" + Constants.INDEXLABEL_PARAM + "=" + HTMLUtils.escapeHtmlValues(HTMLUtils.encode(I18N.getString(
163                    locale, "job.0", job.getJobID()))) + "\">" + I18N.getString(locale, "select.job.for.qa.with.viewerproxy") + "</a></p>");
164            out.println("</td></tr>");
165            out.println("<tr><td>" + I18N.getString(locale, "helptext;select.job.for.qa.with.viewerproxy") + "</td></tr></table>");
166        }
167        out.println("<h3>" + I18N.getString(locale, "subtitle.job.domainconfigurations") + "</h3>");
168        out.println("<table class=\"selection_table\"><tr>");
169        out.println("<th>" + I18N.getString(locale, "table.job.domainconfigurations.domain") + "</th>");
170        out.println("<th>" + I18N.getString(locale, "table.job.domainconfigurations.configuration") + "</th>");
171        out.println("<th>" + I18N.getString(locale, "table.job.domainconfigurations.bytesharvested") + "</th>");
172        out.println("<th>" + I18N.getString(locale, "table.job.domainconfigurations.documentsharvested") + "</th>");
173        out.println("<th>" + I18N.getString(locale, "table.job.domainconfigurations.stopreason") + "</th>");
174        out.println("</tr>");
175
176        DomainDAO ddao = DomainDAO.getInstance();
177        int rowcount = 0;
178        for (Map.Entry<String, String> conf :
179                job.getDomainConfigurationMap().entrySet()) {
180            String domainLink;
181            String configLink;
182            String domainName = conf.getKey();
183            String configName = conf.getValue();
184            if (SiteSection.isDeployed(
185                    Constants.DEFINITIONS_SITESECTION_DIRNAME)) {
186                domainLink =
187                        "<a href=\"/HarvestDefinition/Definitions-edit-domain.jsp?"
188                                + Constants.DOMAIN_PARAM + "="
189                                + HTMLUtils.encodeAndEscapeHTML(domainName) + "\">"
190                                + HTMLUtils.escapeHtmlValues(domainName) + "</a>";
191                configLink =
192                        "<a href=\"/HarvestDefinition/Definitions-edit-domain-config.jsp?"
193                                + Constants.DOMAIN_PARAM + "="
194                                + HTMLUtils.encodeAndEscapeHTML(domainName) + "&amp;"
195                                + Constants.CONFIG_NAME_PARAM + "="
196                                + HTMLUtils.encodeAndEscapeHTML(configName) + "&amp;"
197                                + Constants.EDIT_CONFIG_PARAM + "=1\">"
198                                + HTMLUtils.escapeHtmlValues(configName)  + "</a>";
199            } else {
200                domainLink = HTMLUtils.escapeHtmlValues(domainName);
201                configLink = HTMLUtils.escapeHtmlValues(configName);
202            }
203            HarvestInfo hi = ddao.getDomainJobInfo(job, domainName,
204                    configName);
205
206            out.println("<tr class=" + HTMLUtils.getRowClass(rowcount++) + ">");
207            out.println("<td>" + domainLink + "</td>");
208            out.println("<td>" + configLink + "</td>");
209            if (hi == null) {
210                out.println("<td>-</td><td>-</td><td>-</td>");
211                } else {
212                out.println("<td>" + hi.getSizeDataRetrieved() + "</td>");
213                out.println("<td>" + hi.getCountObjectRetrieved() + "</td>");
214                out.println("<td>" + hi.getStopReason().getLocalizedString(locale) + "</td>");
215                out.println("</tr>");
216            }
217        }
218
219        out.println("</table>");
220        out.println("<h3>" + I18N.getString(locale, "subtitle.job.seedlist") + "</h3>");
221        out.println("<p>");
222
223        for (String seed : job.getSortedSeedList()) {
224            String url;
225            if (!seed.matches(Constants.PROTOCOL_REGEXP)) {
226                url = "http://" + seed;
227            } else {
228                url = seed;
229            }
230            // If length of seed exceeds Constants.MAX_SHOWN_SIZE_OF_URL
231            // show only Constants.MAX_SHOWN_SIZE_OF_URL of the seed, and append
232            // the string " .."
233            String shownSeed = StringUtils.makeEllipsis(seed,
234                    Constants.MAX_SHOWN_SIZE_OF_URL);
235
236            out.println("<a target=\"viewerproxy\" href=\"" + HTMLUtils.escapeHtmlValues(url) + "\">" +
237                    HTMLUtils.escapeHtmlValues(shownSeed) + "</a><br/>");
238        }
239        out.println("</p>");
240
241
242        if (SiteSection.isDeployed(Constants.QA_SITESECTION_DIRNAME)
243                && job.getStatus().ordinal() > JobStatus.STARTED.ordinal()) {
244            //make links to reports from harvest, extracted from viewerproxy.
245            String harvestprefix = job.getHarvestFilenamePrefix();
246
247            out.println("<h3>" +  I18N.getString(locale, "subtitle;reports.for.job") + "</h3>");
248            out.println("<p><a href=\"/QA/QA-getreports.jsp?jobid=" + jobID + "\">" + I18N.getString(locale, "harvest.reports") + "</a></p>");
249            out.println("<p><a href=\"/QA/QA-getfiles.jsp?jobid=" + jobID + "&harvestprefix=" + harvestprefix + "\">" + I18N.getString(locale, "harvest.files") + "</a></p>");
250
251            //search in crawl-logs
252            out.println("<p>");
253            out.println("<form method=\"post\" action=\"/QA/QA-searchcrawllog.jsp\">");
254            out.println("<input type=\"hidden\" name=\"" + dk.netarkivet.viewerproxy.webinterface.Constants.JOBID_PARAM + "\" value=\"" + jobID + "\" />");
255            out.println("<input type=\"submit\" value=\"" + I18N.getString(locale, "display.crawl.log.lines.matching.regexp") + "\" />");
256            out.println("<input type=\"text\" name=\"" + dk.netarkivet.viewerproxy.webinterface.Constants.REGEXP_PARAM + "\" size=\"60\"/>");
257            out.println("</form></p>");
258
259            //make submit button for recalling crawl.log relevant for the specific domains.
260            out.println("<p>");
261
262            out.println("<form method=\"post\" action=\"/QA/QA-searchcrawllog.jsp\">");
263            out.println("<input type=\"hidden\" name=\"" + dk.netarkivet.viewerproxy.webinterface.Constants.JOBID_PARAM + "\" value=\"" + jobID + "\" />");
264            out.println("<input type=\"submit\" value=\"" + I18N.getString(locale, "crawl.log.lines.for.domain") + "\" />");
265            out.println("<select name=\"" + dk.netarkivet.viewerproxy.webinterface.Constants.DOMAIN_PARAM + "\">");
266            for (String domain : job.getDomainConfigurationMap().keySet()) {
267                out.println("<option value=" + HTMLUtils.escapeHtmlValues(domain) + ">" + HTMLUtils.escapeHtmlValues(domain) + "</option>");
268            }
269            out.println("</select>");
270            out.println("</form>");
271            out.println("</p>");
272        }
273
274
275        out.println("<h3>" + I18N.getString(locale, "subtitle.job.harvesttemplate",
276        HTMLUtils.escapeHtmlValues((job.getOrderXMLName()))) + "</h3>");
277
278        // make link to harvest template for job
279        String link = "/History/Harveststatus-download-job-harvest-template.jsp?"
280                + "JobID=" + job.getJobID();
281        String linkWithrequestedType = link + "&requestedContentType=text/plain";
282
283        out.println("<a href=\"" + link + "\">" + I18N.getString(locale, "show.job.0.harvesttemplate", job.getJobID()) + "</a>&nbsp;(<a href=\"" +
284                linkWithrequestedType + "\">text/plain</a>)");
285
286        if (job.getUploadErrors() != null && job.getUploadErrors().length() != 0) {
287            out.println("<a id=\"uploaderror\"></a>");
288            out.println("<h3>" + I18N.getString(locale, "subtitle.job.uploaderror.details") + "</h3>");
289            out.println("<pre>" + HTMLUtils.escapeHtmlValues(job.getUploadErrorDetails()) + "</pre>");
290        }
291        if (job.getHarvestErrors() != null && job.getHarvestErrors().length() != 0) {
292            out.println("<a id=\"harvesterror\"></a>");
293            out.println("<h3>" + I18N.getString(locale, "subtitle.job.harvesterror.details") + "</h3>");
294            out.println("<pre>" + HTMLUtils.escapeHtmlValues(job.getHarvestErrorDetails()) + "</pre>");
295        }
296    }
297}