source: branches/3.3-stable/www/views/jobs/view_job.jsp @ 6510

Last change on this file since 6510 was 6510, checked in by Nicklas Nordborg, 8 years ago

References #1786: Create one log entry for every changed property instead of building a comma-separated summary

Use ADD and REMOVE change type instead of CREATE/DELETE for changes that are not made on the main item. For example, when adding an annotation or data file to an item.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 18.4 KB
Line 
1<%-- $Id: view_job.jsp 6510 2014-08-11 07:29:17Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2005 Nicklas Nordborg
4  Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg, Gregory Vincic
5  Copyright (C) 2007 Nicklas Nordborg
6
7  This file is part of BASE - BioArray Software Environment.
8  Available at http://base.thep.lu.se/
9
10  BASE is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License
12  as published by the Free Software Foundation; either version 3
13  of the License, or (at your option) any later version.
14
15  BASE is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with BASE. If not, see <http://www.gnu.org/licenses/>.
22  ------------------------------------------------------------------
23
24  @author Nicklas
25  @version 2.0
26--%>
27<%@ page pageEncoding="UTF-8" session="false"
28  import="net.sf.basedb.core.SessionControl"
29  import="net.sf.basedb.core.DbControl"
30  import="net.sf.basedb.core.SystemItems"
31  import="net.sf.basedb.core.Item"
32  import="net.sf.basedb.core.ItemContext"
33  import="net.sf.basedb.core.Permission"
34  import="net.sf.basedb.core.Job"
35  import="net.sf.basedb.core.JobAgent"
36  import="net.sf.basedb.core.BasicItem"
37  import="net.sf.basedb.core.Nameable"
38  import="net.sf.basedb.core.File"
39  import="net.sf.basedb.core.Path"
40  import="net.sf.basedb.core.User"
41  import="net.sf.basedb.core.ChangeHistory"
42  import="net.sf.basedb.core.ItemResultIterator"
43  import="net.sf.basedb.core.ItemQuery"
44  import="net.sf.basedb.core.ItemResultList" 
45  import="net.sf.basedb.core.PermissionDeniedException"
46  import="net.sf.basedb.core.PluginDefinition"
47  import="net.sf.basedb.core.PluginConfiguration"
48  import="net.sf.basedb.core.PluginType"
49  import="net.sf.basedb.core.ParameterInfo"
50  import="net.sf.basedb.core.query.Orders"
51  import="net.sf.basedb.core.query.Hql"
52  import="net.sf.basedb.core.plugin.GuiContext"
53  import="net.sf.basedb.core.plugin.NonRestartable"
54  import="net.sf.basedb.core.plugin.Plugin"
55  import="net.sf.basedb.core.signal.SignalTransporter"
56  import="net.sf.basedb.core.signal.Signal"
57  import="net.sf.basedb.plugins.util.Parameters"
58  import="net.sf.basedb.clients.web.Base"
59  import="net.sf.basedb.clients.web.ChangeHistoryUtil"
60  import="net.sf.basedb.clients.web.util.HTML"
61  import="net.sf.basedb.util.Values"
62  import="net.sf.basedb.util.formatter.Formatter"
63  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
64  import="java.util.Date"
65  import="java.util.Map"
66  import="java.util.Set"
67  import="java.util.List"
68  import="java.util.Collections"
69  import="java.util.Collection"
70%>
71<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
72<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
73<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
74<%!
75  private static final Item itemType = Item.JOB;
76  private static final GuiContext guiContext = new GuiContext(itemType, GuiContext.Type.ITEM);
77
78  private String getItemName(BasicItem item)
79  {
80    String itemName = "";
81    if (item instanceof File)
82    {
83      itemName = ((File)item).getPath().toString();
84    }
85    else if (item instanceof Nameable)
86    {
87      itemName = ((Nameable)item).getName();
88    }
89    else
90    {
91      itemName = item.toString();
92    }
93    return itemName;
94  }
95%>
96<%
97final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
98final String ID = sc.getId();
99final ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, null);
100final int itemId = cc.getId();
101final String tab = Values.getString(request.getParameter("tab"), "properties");
102final float scale = Base.getScale(sc);
103final DbControl dc = sc.newDbControl();
104try
105{
106  Job job = Job.getById(dc, itemId);
107  String title = "View job -- " + HTML.encodeTags(job.getName());
108 
109  final boolean writePermission = job.hasPermission(Permission.WRITE);
110  final boolean deletePermission = job.hasPermission(Permission.DELETE);
111  final boolean isRemoved = job.isRemoved();
112  final boolean isUsed = isRemoved && job.isUsed();
113  final boolean deletePermanentlyPermission = deletePermission && !isUsed;
114 
115  boolean readCurrentConfig = true;
116  PluginConfiguration currentConfig = null;
117  try
118  {
119    currentConfig = job.getPluginConfiguration();
120  }
121  catch (PermissionDeniedException ex)
122  {
123    readCurrentConfig = false;
124  }
125  boolean readAgent = true;
126  JobAgent agent = null;
127  try
128  {
129    agent = job.getJobAgent();
130  }
131  catch (PermissionDeniedException ex)
132  {
133    readAgent = false;
134  }
135
136  int parameterVersion = job.getParameterVersion();
137  int latestParameterVersion = currentConfig == null ? parameterVersion : currentConfig.getParameterVersion();
138
139  final Job.Status status = job.getStatus();
140  final boolean autoUpdate = status == Job.Status.WAITING || 
141    status == Job.Status.PREPARED || status == Job.Status.EXECUTING || status == Job.Status.ABORTING;
142  Formatter<Date> dateFormatter = FormatterFactory.getDateFormatter(sc);
143  Formatter<Date> dateTimeFormatter = FormatterFactory.getDateTimeFormatter(sc);
144  Set<String> jobParameters = job.getParameterNames();
145  File logFile = null;
146  if (!autoUpdate && jobParameters != null && jobParameters.contains(Parameters.LOGFILE_PARAMETER))
147  {
148    try
149    {
150      Object temp = job.getParameterValue(Parameters.LOGFILE_PARAMETER);
151      if (temp instanceof File)
152      {
153        logFile = (File)temp;
154      }
155      else if (temp instanceof String)
156      {
157        logFile = File.getByPath(dc, new Path((String)temp, Path.Type.FILE), false);
158      }
159    }
160    catch (Throwable t)
161    {}
162  }
163 
164  // Check if the job can be aborted
165  boolean supportsAbort = false; 
166 
167  // The status must be executable or EXECUTING
168  if ((status == Job.Status.EXECUTING || status.isExecutable()) && writePermission)
169  {
170    // Check if a signal-transporter exists
171    try
172    {
173      SignalTransporter signalTransporter = job.getSignalTransporter();
174      if (signalTransporter == null)
175      {
176        // The job is only abortable if it is waiting
177        supportsAbort = status == Job.Status.WAITING;
178      }
179      else
180      {
181        // Otherwise we must check with the signal transporter
182        Collection<Signal> supportedSignals = signalTransporter.getSupportedSignals();
183        supportsAbort = supportedSignals == null || supportedSignals.contains(Signal.ABORT);
184      }
185    }
186    catch (Exception ex)
187    {}
188  }
189  if (autoUpdate) job.requestStatusUpdate();
190  %>
191  <base:page type="popup" title="<%=title%>" id="view-page"> 
192  <base:head scripts="tabcontrol-2.js,table.js,~jobs.js" 
193    styles="tabcontrol.css,progressbar.css,table.css" />
194  <base:body data-read-only="1">
195    <h1><%=title%> <base:help tabcontrol="main" /></h1>
196    <div id="page-data" 
197      data-item-id="<%=itemId%>"
198      data-job-parameter-version="<%=parameterVersion %>"
199      data-latest-parameter-version="<%=latestParameterVersion %>"
200      data-job-status="<%=status.name()%>"
201      data-auto-update="<%=autoUpdate ? 1 : 0 %>"
202    ></div>
203
204    <t:tabcontrol id="main" 
205      subclass="content dialogtabcontrol"
206      active="<%=tab%>" position="bottom">
207    <t:tab id="properties" title="Properties" helpid="job.view.properties">
208      <table class="fullform outlined">
209      <%
210      if (isRemoved)
211      {
212        %>
213        <tr>
214          <td colspan="2" style="background: #E8E8E8; border-bottom: 1px solid #A0A0A0;">
215          <div class="itemstatus">
216            <base:icon 
217              id="btnDeletePermanently"
218              image="deleted.png"
219              data-notify="btnDeletePermanently"
220              enabled="<%=deletePermanentlyPermission %>"
221              tooltip="<%=deletePermanentlyPermission ? "Permanently delete this item" : null%>"
222              visible="<%=isRemoved%>"> This item has been flagged for deletion<br></base:icon>
223            <base:icon
224              id="btnUsingItems"
225              image="used.png" 
226              tooltip="Show the items that are using this one"
227              visible="<%=isUsed%>"> This item is used by other items and can't be permanently deleted<br></base:icon>
228          </div>
229          </td>
230        </tr>
231        <%
232      }
233      %>
234      <tr>
235        <th style="border-top: 0px;">Name</th>
236        <td><%=HTML.encodeTags(job.getName())%></td>
237      </tr>
238      <tr>
239        <th>Plugin</th>
240        <td>
241          <base:propertyvalue item="<%=job%>" property="pluginDefinition.name" /> 
242          <%=job.getPluginVersion() == null ?
243            "" : "(version " + HTML.encodeTags(job.getPluginVersion()) + ")"%>
244        </td>
245      </tr>
246      <%
247      if (currentConfig != null)
248      {
249        %>
250        <tr>
251          <th class="subprompt">- configuration</th>
252          <td>
253            <base:propertyvalue item="<%=job%>" property="pluginConfiguration.name" />
254          </td>
255        </tr>
256        <%
257      }
258      %>
259      <tr>
260        <th>User</th>
261        <td>
262          <base:propertyvalue item="<%=job%>" property="owner.name" />
263        </td>
264      </tr>
265      <tr>
266        <th>Experiment</th>
267        <td>
268          <base:propertyvalue item="<%=job%>" property="experiment.name" />
269        </td>
270      </tr>
271      <tr>
272        <th>Status</th>
273        <td>
274          <div class="<%=job.getStatus() == Job.Status.ERROR ? "error messagecontainer" : ""%>" style="margin: 1px 0px;">
275          <%=job.getStatus()%><%=job.isDryRun() ? " (dry-run)" : "" %>:
276          <span id="message" ><%=HTML.niceFormat(job.getStatusMessage())%></span>
277          </div>
278        </td>
279      </tr>
280      <tr>
281        <th class="subprompt">- percent complete</th>
282        <td>
283          <table class="progressbar">
284          <tr>
285          <td>
286            <table class="bar" style="width: 200px;">
287            <tr>
288              <%
289              int percent = job.getPercentComplete();
290              %>
291              <td id="percentDone" class="percentDone" style="width: <%=percent%>%; <%=percent <= 0 ? "display: none;" : ""%>">&nbsp;</td>
292              <td id="percentRemain" class="percentRemain" style="width: <%=100-percent%>%; <%=percent == 100 || percent == -1 ? "display: none;" : ""%>">&nbsp;</td>
293              <td id="percentUnknown" class="percentUnknown" style="width: 100%; <%=percent != -1 ? "display: none;" : "" %>">unknown</td>
294            </tr>
295            </table>
296          </td>
297          <td id="percentText" class="percentText" 
298            style="<%=percent < 0 ? "display: none;" : "" %>"><%=percent%>%</td>
299            <%
300            if (logFile != null)
301            {
302              %>
303              <td style="padding-left: 10px;"><base:button 
304                subclass="link auto-init"
305                data-auto-init="view-file"
306                data-file-id="<%=logFile.getId()%>"
307                image="view.png" 
308                title="View log&hellip;"
309                tooltip="View the log file with detailed information about this job"
310                /></td>
311              <%
312            }
313            %>
314          </tr>
315          </table>
316        </td>
317      </tr>
318      <tr>
319        <th>Description</th>
320        <td><%=HTML.niceFormat(job.getDescription())%></td>
321      </tr>
322      <tr>
323        <th>Created</th>
324        <td>
325          <%=dateTimeFormatter.format(job.getCreated())%>
326        </td>
327      </tr>
328      <tr>
329        <th class="subprompt">- scheduled</th>
330        <td>
331          <%=dateTimeFormatter.format(job.getScheduled())%>
332        </td>
333      </tr>
334      <tr>
335        <th class="subprompt">- priority</th>
336        <td>
337          <%=job.getPriority()%> (1 = highest, 10 = lowest)
338        </td>
339      </tr>
340      <tr>
341        <th>Running time</th>
342        <td id="runningTime">
343          <%
344          Date started = job.getStarted();
345          if (started != null)
346          {
347            Date ended = job.getEnded();
348            if (ended == null) ended = new Date();
349            long runningTime = ended.getTime() - started.getTime();
350            %>
351            <%=Values.formatTime(runningTime / 1000)%>
352            <%
353          }
354          %>
355        </td>
356      </tr>
357      <tr>
358        <th class="subprompt">- started</th>
359        <td>
360          <%=dateTimeFormatter.format(job.getStarted())%>
361        </td>
362      </tr>
363      <tr>
364        <th class="subprompt">- ended</th>
365        <td>
366          <%=dateTimeFormatter.format(job.getEnded())%>
367        </td>
368      </tr>
369      <tr>
370        <th>Server</th>
371        <td>
372          <%=HTML.encodeTags(job.getServer())%>
373        </td>
374      </tr>
375      <tr>
376        <th>External ID</th>
377        <td>
378          <%=HTML.encodeTags(job.getExternalId())%>
379        </td>
380      </tr>
381      <tr>
382        <th>Job agent</th>
383        <td><%=Base.getEncodedName(agent, !readAgent)%></td>
384      </tr>
385      <tr class="dynamic">
386        <th></th>
387        <td></td>
388      </tr>
389      </table>
390      </t:tab>
391      <%
392      if (job.getStackTrace() != null)
393      {
394        %>
395        <t:tab id="stacktrace" title="Stack trace" helpid="job.view.stacktrace">
396          <div class="stacktrace" style="padding: 0.5em;"><%=HTML.encodeTags(job.getStackTrace().replaceAll("\t", "  "))%></div>
397        </t:tab>
398        <%
399      }
400      %>
401      <t:tab id="parameters" title="Parameters" helpid="job.view.parameters">
402        <table class="fullform outlined">
403        <tbody class="sectionheader">
404          <tr>
405            <th colspan="2">Job parameters</th>
406          </tr>
407        </tbody>
408        <tbody>
409        <%
410        List<String> names = new java.util.ArrayList<String>(jobParameters);
411        Collections.sort(names);
412        for (String name : names)
413        {
414          StringBuilder sb = new StringBuilder();
415          String displayValue = "";
416          String description = "";
417          try
418          {
419            ParameterInfo pi = job.getParameterInfo(name);
420            if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
421            description = HTML.encodeTags(pi.getDescription());
422            List<?> values = pi.getValues();
423            int i = 0;
424            for (Object value : values)
425            {
426              if (value != null)
427              {
428                if (i > 0) sb.append(", ");
429                i++;
430                if (value instanceof BasicItem)
431                {
432                  sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
433                }
434                else if (value instanceof Date)
435                {
436                  sb.append(dateFormatter.format((Date)value));
437                }
438                else
439                {
440                  sb.append(HTML.encodeTags(value.toString()));
441                }
442              }
443            }
444            displayValue = sb.toString();
445          }
446          catch (Throwable ex)
447          {
448            displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
449          }
450          %>
451          <tr>
452            <th><span title="<%=description%>"><%=name%></span></th>
453            <td>
454              <%=displayValue%>
455            </td>
456          </tr>
457          <%
458        }
459        %>
460        <%
461        if (!readCurrentConfig)
462        {
463          %>
464          </tbody>
465          <tbody class="sectionheader">
466            <tr>
467              <th colspan="2">Plugin configuration parameters</th>
468            </tr>
469          </tbody>
470          <tbody>
471          <tr>
472            <th></th>
473            <td><i>- denied -</i></td>
474          </tr>
475          <%
476        }
477        else if (currentConfig != null)
478        {
479          %>
480          </tbody>
481          <tbody class="sectionheader">
482            <tr>
483              <th colspan="2">Plugin configuration parameters</th>
484            </tr>
485          </tbody>
486          <tbody>
487          <tr>
488            <th><span 
489              title="The version of the parmeters used for this job, current version in paranthesis">Parameter version</span></td>
490            <td><%=parameterVersion%> (<%=latestParameterVersion %>)</th>
491          </tr>
492          <%
493          names = new java.util.ArrayList<String>(currentConfig.getParameterNames(parameterVersion));
494          Collections.sort(names);
495          for (String name : names)
496          {
497            StringBuilder sb = new StringBuilder();
498            String displayValue = "";
499            String description = "";
500            try
501            {
502              ParameterInfo pi = currentConfig.getParameterInfo(name, parameterVersion);
503              if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
504              description = HTML.encodeTags(pi.getDescription());
505              List<?> values = pi.getValues();
506              int i = 0;
507              for (Object value : values)
508              {
509                if (value != null)
510                {
511                  if (i > 0) sb.append(", ");
512                  i++;
513                  if (value instanceof BasicItem)
514                  {
515                    sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
516                  }
517                  else if (value instanceof Date)
518                  {
519                    sb.append(dateFormatter.format((Date)value));
520                  }
521                  else
522                  {
523                    sb.append(HTML.encodeTags(value.toString()));
524                  }
525                }
526              }
527              displayValue = sb.toString();
528            }
529            catch (Throwable ex)
530            {
531              displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
532            }
533            %>
534            <tr>
535              <th><span title="<%=description%>"><%=name%></span></th>
536              <td>
537                <%=displayValue%>
538              </td>
539            </tr>
540            <%
541          }
542          %>
543          <%
544        }
545        %>
546        <tr class="dynamic">
547          <th></th>
548          <td></td>
549        </tr>
550        </tbody>
551        </table>
552      </t:tab>
553     
554      <t:tab id="changes" title="Changed items"
555        tooltip="Display a log of all modifications made by this job"
556        visible="<%=!autoUpdate && ChangeHistoryUtil.showChangeHistoryTab(sc) %>">
557        <%
558        ItemQuery<ChangeHistory> query = ChangeHistory.getChangesBy(job);
559        query.order(Orders.asc(Hql.property("id")));
560        ItemResultIterator<ChangeHistory> changes = query.iterate(dc);
561        int numChanges = 0;
562        %>
563        <tbl:table 
564          id="history" columns="all" 
565          subclass="fulltable" style="border-bottom: 0px;">
566          <tbl:columndef id="changeType" title="Change type" />
567          <tbl:columndef id="item" title="Item" />
568          <tbl:columndef id="info" title="Info" />
569         
570          <tbl:data style="top: 0px;">
571            <tbl:headers>
572              <tbl:headerrow>
573                <tbl:columnheaders />
574              </tbl:headerrow>
575            </tbl:headers>
576            <tbl:rows>
577            <%
578            while (changes.hasNext())
579            {
580              numChanges++;
581              ChangeHistory change = changes.next();
582              %>
583              <tbl:row>
584                <tbl:cell column="changeType"><%=change.getChangeType()%></tbl:cell>
585                <tbl:cell column="item"><%=ChangeHistoryUtil.getItem(dc, change, false, false)%></tbl:cell>
586                <tbl:cell column="info"><%=HTML.encodeTags(change.getChangeInfo())%></tbl:cell>
587              </tbl:row>
588              <%
589            }
590            if (numChanges == 0)
591            {
592              %>
593              <tbl:panel clazz="messagepanel">
594                <div class="messagecontainer note">
595                No log entries found for this job. NOTE! This job may have made
596                other changes that are not recorded by the logging mechanism.
597                </div>
598              </tbl:panel>
599              <%
600            }
601            %>
602            </tbl:rows>
603          </tbl:data>
604        </tbl:table>
605      </t:tab>
606      </t:tabcontrol>
607 
608    <base:buttongroup subclass="dialogbuttons">
609      <%
610      if (supportsAbort)
611      {
612        %>
613        <base:button id="btnAbort" title="Abort&hellip;" image="abort.png" />
614        <%
615      }
616      %>
617      <%
618      if (job.getStatus() == Job.Status.ERROR && job.getJobType() == Job.Type.RUN_PLUGIN)
619      {
620        boolean restartable = !job.getPluginDefinition().supports("net.sf.basedb.core.plugin.NonRestartable");       
621        if (restartable)
622        {
623          %>
624          <base:button 
625            id="btnRestartJob" 
626            title="Restart job" 
627            image="refresh.png" 
628            tooltip="Try to run this job again with the same parameters"
629          />
630          <base:button 
631            id="btnReconfigureJob"
632            title="Re-configure job"
633            image="runplugin.png"
634            tooltip="Change the parameters for this job and try again"
635            visible="<%=job.hasContext()%>"
636          />
637          <%
638        }
639      }
640      if (job.getStatus() == Job.Status.DONE && job.isDryRun())
641      {
642        %>
643        <base:button 
644          id="btnRestartJob"
645          data-clear-dry-run="1"
646          title="Really run" 
647          image="refresh.png" 
648          tooltip="Run this dry-run job for real"
649        />
650        <%
651      }
652      %>
653      <base:button id="close" title="Close" />
654    </base:buttongroup>
655  </base:body>
656  </base:page>
657  <%
658}
659finally
660{
661  if (dc != null) dc.close();
662}
663
664%>
Note: See TracBrowser for help on using the repository browser.