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) + "&" 195 + Constants.CONFIG_NAME_PARAM + "=" 196 + HTMLUtils.encodeAndEscapeHTML(configName) + "&" 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> (<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}