source: trunk/www/views/jobs/view_job.jsp @ 5556

Last change on this file since 5556 was 5556, checked in by Nicklas Nordborg, 13 years ago

References #1570: Use JSON for data transport in AJAX calls

Implemented this for lazy loading of child nodes in the item overview and for the job progress reporter.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 20.8 KB
Line 
1<%-- $Id: view_job.jsp 5556 2011-01-28 08:15:28Z 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 plug-in supports the "Abort" signal
165  boolean supportsAbort = status == Job.Status.WAITING && writePermission;
166  if (status == Job.Status.EXECUTING && writePermission)
167  {
168    try
169    {
170      SignalTransporter signalTransporter = job.getSignalTransporter();
171      Collection<Signal> supportedSignals = signalTransporter != null ? 
172        signalTransporter.getSupportedSignals() : null;
173      supportsAbort = signalTransporter != null && 
174        (supportedSignals == null || supportedSignals.contains(Signal.ABORT));
175    }
176    catch (Exception ex)
177    {}
178  }
179  %>
180  <base:page type="popup" title="<%=title%>"> 
181  <base:head scripts="tabcontrol.js,table.js,ajax.js,json2.js" styles="tabcontrol.css,progressbar.css,table.css">
182  <script language="JavaScript">
183  function autoUpdate()
184  {
185    var autoUpdate = <%=autoUpdate ? "true" : "false"%>;
186    if (autoUpdate) sendProgressUpdateRequest();
187  }
188  function abortJob()
189  {
190    if (confirm('Are you sure? This action may not be undone'))
191    {
192      location.href = 'index.jsp?ID=<%=ID%>&cmd=AbortJob&item_id=<%=itemId%>';
193    }
194  }
195  function restartJob(clearDryRun)
196  {
197    var parameterVersion = <%=parameterVersion%>;
198    var latestVersion = <%=latestParameterVersion%>;
199    var useLatestConfiguration = 0;
200    if (parameterVersion != latestVersion)
201    {
202      var msg = 'The configuration parameters for the plugin has changed since\n';
203      msg += 'the job was added to the job queue. Do you want to use the new\n';
204      msg += 'configuration parameters?\n\n';
205      msg += 'Ok / Yes = Use the new parameters (version = '+latestVersion + ')\n';
206      msg += 'Cancel / No = Use the current parameters (version = ' + parameterVersion + ')';
207      if (confirm(msg)) useLatestConfiguration = 1;
208    }
209    var url = 'index.jsp?ID=<%=ID%>&cmd=RestartJob&item_id=<%=itemId%>';
210    url += '&useLatestConfiguration='+useLatestConfiguration;
211    if (clearDryRun) url += '&clearDryRun=' + clearDryRun;
212    location.href = url;
213  }
214  function reconfigureJob()
215  {
216    location.href = '../../common/plugin/index.jsp?ID=<%=ID%>&cmd=ConfigureJob&job_id=<%=itemId%>';
217  }
218 
219    function deleteItemPermanently()
220    {
221      Main.deleteItemPermanently('<%=ID%>', true, '<%=itemType.name()%>', <%=itemId%>, '&callback=itemDeleted');
222    }
223    function itemDeleted()
224    {
225      location.href = getRoot() + 'common/close_popup.jsp?ID=<%=ID%>&refresh_opener=1&wait=0';
226    }
227    function showUsingItems()
228    {
229      Main.showUsingItems('<%=ID%>', '<%=itemType.name()%>', <%=itemId%>);
230    }
231   
232    var lastStatus = '<%=status.name()%>';
233    function sendProgressUpdateRequest()
234    {
235      var request = Ajax.getXmlHttpRequest();
236      var url = 'ajax.jsp?ID=<%=ID%>&cmd=GetProgress&item_id=<%=itemId%>&'+Math.random();
237      request.open("GET", url, true);
238      Ajax.setReadyStateHandler(request, progressUpdateCallback);
239      request.send(null);
240    }
241    function progressUpdateCallback(request)
242    {
243      var progress = Ajax.parseJsonResponse(request.responseText);
244      if (progress && progress.status == 'ok')
245      {
246        var status = progress.jobStatus;
247        var message = progress.message;
248        var percentComplete = progress.percentComplete;
249        var runningTime = progress.runningTime;
250       
251        if (lastStatus != status) location.reload();
252        if (status == 'EXECUTING')
253        {
254          displayProgress(percentComplete, message, runningTime);
255        }
256      }
257      setTimeout('sendProgressUpdateRequest()', 1500);
258    }
259
260    function displayProgress(percentDone, message, runningTime)
261    {
262      // Percent complete
263      var doneElement = document.getElementById('percentDone');
264      var remainElement = document.getElementById('percentRemain');
265      var unknownElement = document.getElementById('percentUnknown');
266      if (percentDone == -1)
267      {
268        Main.hide('percentDone');
269        Main.hide('percentRemain');
270        Main.show('percentUnknown');
271        Main.hide('percent');
272      }
273      else
274      {
275        Main.hide('percentUnknown');
276        Main.show('percent');
277        document.getElementById('percent').innerHTML = '&nbsp;' + percentDone+'%';
278        doneElement.style.width = percentDone+'%';
279        remainElement.style.width = (100-percentDone)+'%';
280        Main.showHide('percentDone', percentDone > 0);
281        Main.showHide('percentRemain', percentDone < 100);
282      }
283
284      // Message
285      document.getElementById('message').innerHTML = message;
286
287      // Running time
288      document.getElementById('runningTime').innerHTML = runningTime;
289    }
290  </script>
291  </base:head>
292  <base:body onload="autoUpdate()">
293    <h3 class="docked"><%=title%> <base:help tabcontrol="main" /></h3>
294    <t:tabcontrol id="main" active="<%=tab%>" position="bottom" contentstyle="<%="height: "+(int)(scale*350)+"px;"%>">
295    <t:tab id="properties" title="Properties" helpid="job.view.properties">
296
297      <%
298      if (job.isRemoved())
299      {
300        %>
301        <div class="itemstatus">
302          <base:icon 
303            image="<%=deletePermanentlyPermission ? "deleted.gif" : "deleted_disabled.gif"%>"
304            onclick="<%=deletePermanentlyPermission ? "deleteItemPermanently()" : null%>"
305            tooltip="<%=deletePermanentlyPermission ? "Permanently delete this item" : null%>"
306            visible="<%=isRemoved%>"> This item has been flagged for deletion<br></base:icon>
307          <base:icon image="used.gif" 
308            onclick="showUsingItems()"
309            tooltip="Show the items that are using this one"
310            visible="<%=isUsed%>"> This item is used by other items and can't be permanently deleted<br></base:icon>
311        </div>
312        <%
313      }
314      %>
315      <table class="form" cellspacing=0>
316      <tr>
317        <td class="prompt">Name</td>
318        <td><%=HTML.encodeTags(job.getName())%></td>
319      </tr>
320      <tr>
321        <td class="prompt">Description</td>
322        <td><%=HTML.niceFormat(job.getDescription())%></td>
323      </tr>
324      <tr valign="top">
325        <td class="prompt">Priority</td>
326        <td>
327          <%=job.getPriority()%> (1 = highest, 10 = lowest)
328        </td>
329      </tr>
330      <tr valign="top">
331        <td class="prompt">Status</td>
332        <td <%=job.getStatus() == Job.Status.ERROR ? "class=\"error\" style=\"text-align: left;\"" : "" %>>
333          <%=job.getStatus()%><%=job.isDryRun() ? " (dry-run)" : "" %>:
334          <span id="message"><%=HTML.niceFormat(job.getStatusMessage())%></span>
335        </td>
336      </tr>
337      <tr valign="middle">
338        <td class="prompt">Percent complete</td>
339        <td>
340          <table border=0 cellspacing=0 cellpadding=0>
341          <tr>
342          <td valign="middle" style="max-width: 100px;">
343            <table width="100px" class="progressbar" border=0 cellspacing=0 cellpadding=0>
344            <tr>
345              <%
346              int percent = job.getPercentComplete();
347              %>
348              <td id="percentDone" class="done" width="<%=percent%>%" 
349                style="<%=percent <= 0 ? "display: none;" : ""%>">&nbsp;</td>
350              <td id="percentRemain" class="remain" width="<%=100-percent%>%"
351                style="<%=percent == 100 || percent == -1 ? "display: none;" : ""%>">&nbsp;</td>
352              <td id="percentUnknown" width="100%" class="unknown"
353                style="<%=percent != -1 ? "display: none" : "" %>">unknown</td>
354            </tr>
355            </table>
356          </td>
357          <td id="percent" 
358            style="<%=percent < 0 ? "display: none;" : "" %>">&nbsp;<%=percent%>%</td>
359          <%
360          if (logFile != null)
361          {
362            %>
363            <td valign="middle" style="padding-left: 10px;"><base:button image="view.gif" 
364                title="View log&hellip;"
365                onclick="<%="Main.viewFile('" + ID + "', " + logFile.getId() + ")"%>"
366                tooltip="View the log file with detailed information about this job"
367                /></td>
368              <%
369            }
370            %>
371          </tr>
372          </table>
373        </td>
374      </tr>
375      <tr valign="top">
376        <td class="prompt">Created</td>
377        <td>
378          <%=dateTimeFormatter.format(job.getCreated())%>
379        </td>
380      </tr>
381      <tr valign="top">
382        <td class="prompt">Scheduled</td>
383        <td>
384          <%=dateTimeFormatter.format(job.getScheduled())%>
385        </td>
386      </tr>
387      <tr valign="top">
388        <td class="prompt">Started</td>
389        <td>
390          <%=dateTimeFormatter.format(job.getStarted())%>
391        </td>
392      </tr>
393      <tr valign="top">
394        <td class="prompt">Ended</td>
395        <td>
396          <%=dateTimeFormatter.format(job.getEnded())%>
397        </td>
398      </tr>
399      <tr valign="top">
400        <td class="prompt">Running time</td>
401        <td id="runningTime">
402          <%
403          Date started = job.getStarted();
404          if (started != null)
405          {
406            Date ended = job.getEnded();
407            if (ended == null) ended = new Date();
408            long runningTime = ended.getTime() - started.getTime();
409            %>
410            <%=Values.formatTime(runningTime / 1000)%>
411            <%
412          }
413          %>
414        </td>
415      </tr>
416      <tr valign="top">
417        <td class="prompt">Server</td>
418        <td>
419          <%=HTML.encodeTags(job.getServer())%>
420        </td>
421      </tr>
422      <tr valign="top">
423        <td class="prompt">Job agent</td>
424        <td><%=Base.getEncodedName(agent, !readAgent)%></td>
425      </tr>
426      <tr valign="top">
427        <td class="prompt">User</td>
428        <td>
429          <base:propertyvalue item="<%=job%>" property="owner.name" />
430        </td>
431      </tr>
432      <tr valign="top">
433        <td class="prompt">Experiment</td>
434        <td>
435          <base:propertyvalue item="<%=job%>" property="experiment.name" />
436        </td>
437      </tr>
438      <tr valign="top">
439        <td class="prompt">Plugin</td>
440        <td>
441          <base:propertyvalue item="<%=job%>" property="pluginDefinition.name" /> 
442          <%=job.getPluginVersion() == null ?
443            "" : "(version " + HTML.encodeTags(job.getPluginVersion()) + ")"%>
444        </td>
445      </tr>
446      <tr valign="top">
447        <td class="prompt">Configuration</td>
448        <td>
449          <base:propertyvalue item="<%=job%>" property="pluginConfiguration.name" />
450        </td>
451      </tr>
452      </table>
453      </t:tab>
454      <%
455      if (job.getStackTrace() != null)
456      {
457        %>
458        <t:tab id="stacktrace" title="Stack trace" helpid="job.view.stacktrace">
459          <div style="font-family: monospace">
460          <%=HTML.niceFormat(job.getStackTrace())%>
461          </div>
462        </t:tab>
463        <%
464      }
465      %>
466 
467      <t:tab id="parameters" title="Parameters" helpid="job.view.parameters">
468        <h4>Job parameters</h4>
469        <table class="form" cellspacing=0>
470        <%
471        List<String> names = new java.util.ArrayList<String>(jobParameters);
472        Collections.sort(names);
473        for (String name : names)
474        {
475          StringBuilder sb = new StringBuilder();
476          String displayValue = "";
477          String description = "";
478          try
479          {
480            ParameterInfo pi = job.getParameterInfo(name);
481            if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
482            description = HTML.encodeTags(pi.getDescription());
483            List<?> values = pi.getValues();
484            int i = 0;
485            for (Object value : values)
486            {
487              if (value != null)
488              {
489                if (i > 0) sb.append(", ");
490                i++;
491                if (value instanceof BasicItem)
492                {
493                  sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
494                }
495                else if (value instanceof Date)
496                {
497                  sb.append(dateFormatter.format((Date)value));
498                }
499                else
500                {
501                  sb.append(HTML.encodeTags(value.toString()));
502                }
503              }
504            }
505            displayValue = sb.toString();
506          }
507          catch (Throwable ex)
508          {
509            displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
510          }
511          %>
512          <tr>
513            <td class="prompt"><span title="<%=description%>"><%=name%></span></td>
514            <td>
515              <%=displayValue%>
516            </td>
517          </tr>
518          <%
519        }
520        %>
521        </table>
522
523        <%
524        if (!readCurrentConfig)
525        {
526          %>
527          <h4>Plugin configuration parameters</h4>
528          <i>- denied -</i>
529          <%
530        }
531        else if (currentConfig != null)
532        {
533          %>
534          <h4>Plugin configuration parameters</h4>
535          <table class="form" cellspacing=0>
536          <tr>
537            <td class="prompt"><span 
538              title="The version of the parmeters used for this job, current version in paranthesis">Parameter version</span></td>
539            <td><%=parameterVersion%> (<%=latestParameterVersion %>)</td>
540          </tr>
541          <%
542          names = new java.util.ArrayList<String>(currentConfig.getParameterNames(parameterVersion));
543          Collections.sort(names);
544          for (String name : names)
545          {
546            StringBuilder sb = new StringBuilder();
547            String displayValue = "";
548            String description = "";
549            try
550            {
551              ParameterInfo pi = currentConfig.getParameterInfo(name, parameterVersion);
552              if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
553              description = HTML.encodeTags(pi.getDescription());
554              List<?> values = pi.getValues();
555              int i = 0;
556              for (Object value : values)
557              {
558                if (value != null)
559                {
560                  if (i > 0) sb.append(", ");
561                  i++;
562                  if (value instanceof BasicItem)
563                  {
564                    sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
565                  }
566                  else if (value instanceof Date)
567                  {
568                    sb.append(dateFormatter.format((Date)value));
569                  }
570                  else
571                  {
572                    sb.append(HTML.encodeTags(value.toString()));
573                  }
574                }
575              }
576              displayValue = sb.toString();
577            }
578            catch (Throwable ex)
579            {
580              displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
581            }
582            %>
583            <tr>
584              <td class="prompt"><span title="<%=description%>"><%=name%></span></td>
585              <td>
586                <%=displayValue%>
587              </td>
588            </tr>
589            <%
590          }
591          %>
592          </table>
593          <%
594        }
595        %>
596       
597      </t:tab>
598     
599      <t:tab id="changes" title="Changed items"
600        tooltip="Display a log of all modifications made by this job"
601        visible="<%=!autoUpdate && ChangeHistoryUtil.showChangeHistoryTab(sc) %>">
602        <%
603        ItemQuery<ChangeHistory> query = ChangeHistory.getChangesBy(job);
604        query.order(Orders.asc(Hql.property("id")));
605        ItemResultIterator<ChangeHistory> changes = query.iterate(dc);
606        int numChanges = 0;
607        %>
608        <tbl:table id="history" clazz="itemlist" columns="all">
609          <tbl:columndef id="changeType" title="Change type" />
610          <tbl:columndef id="item" title="Item" />
611          <tbl:columndef id="info" title="Info" />
612         
613          <tbl:data>
614            <tbl:columns>
615            </tbl:columns>
616            <tbl:rows>
617            <%
618            while (changes.hasNext())
619            {
620              numChanges++;
621              ChangeHistory change = changes.next();
622              %>
623              <tbl:row>
624                <tbl:cell column="changeType"><%=change.getChangeType()%> <%=change.getItemType()%></tbl:cell>
625                <tbl:cell column="item"><%=ChangeHistoryUtil.getItem(dc, change, false, false)%></tbl:cell>
626                <tbl:cell column="info"><%=HTML.encodeTags(change.getChangeInfo())%></tbl:cell>
627              </tbl:row>
628              <%
629            }
630            %>
631            </tbl:rows>
632          </tbl:data>
633          <%
634          if (numChanges == 0)
635          {
636            %>
637            <tbl:panel>
638            No log entries found for this job. NOTE! This job may have made
639            other changes that are not recorded by the logging mechanism.
640            </tbl:panel>
641            <%
642          }
643          %>
644        </tbl:table>
645       
646      </t:tab>
647     
648      </t:tabcontrol>
649 
650    <base:buttongroup align="center">
651      <%
652      if (supportsAbort)
653      {
654        %>
655        <base:button onclick="abortJob()" title="Abort&hellip;" image="abort.png" />
656        <%
657      }
658      %>
659      <%
660      if (job.getStatus() == Job.Status.ERROR && job.getJobType() == Job.Type.RUN_PLUGIN)
661      {
662        boolean restartable = !job.getPluginDefinition().supports("net.sf.basedb.core.plugin.NonRestartable");       
663        if (restartable)
664        {
665          %>
666          <base:button onclick="restartJob(0)" title="Restart job" 
667            image="refresh.gif" 
668            tooltip="Try to run this job again with the same parameters"
669          />
670          <base:button onclick="reconfigureJob()" title="Re-configure job"
671            image="runplugin.gif"
672            tooltip="Change the parameters for this job and try again"
673            visible="<%=job.hasContext()%>"
674          />
675          <%
676        }
677      }
678      if (job.getStatus() == Job.Status.DONE && job.isDryRun())
679      {
680        %>
681        <base:button onclick="restartJob(1)" title="Really run" 
682          image="refresh.gif" 
683          tooltip="Run this dry-run job for real"
684        />
685        <%
686      }
687      %>
688      <base:button onclick="window.close()" title="Close" />
689    </base:buttongroup>
690  </base:body>
691  </base:page>
692  <%
693}
694finally
695{
696  if (dc != null) dc.close();
697}
698
699%>
Note: See TracBrowser for help on using the repository browser.