/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.mapred;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.http.HtmlQuoting;
import org.apache.hadoop.mapred.JobHistory.JobInfo;
import org.apache.hadoop.mapred.JobHistory.Keys;
import org.apache.hadoop.mapred.JobTracker.RetireJobInfo;
import org.apache.hadoop.mapreduce.JobACL;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.util.ServletUtil;
import org.apache.hadoop.util.StringUtils;

class JSPUtil {
  static final String PRIVATE_ACTIONS_KEY = "webinterface.private.actions";

  //LRU based cache
  private static final Map<String, JobInfo> jobHistoryCache = 
    new LinkedHashMap<String, JobInfo>(); 

  private static final Log LOG = LogFactory.getLog(JSPUtil.class);

  /**
   * Wraps the {@link JobInProgress} object and contains boolean for
   * 'job view access' allowed or not.
   * This class is only for usage by JSPs and Servlets.
   */
  static class JobWithViewAccessCheck {
    private JobInProgress job = null;
    
    // true if user is authorized to view this job
    private boolean isViewAllowed = true;

    JobWithViewAccessCheck(JobInProgress job) {
      this.job = job;
    }

    JobInProgress getJob() {
      return job;
    }

    boolean isViewJobAllowed() {
      return isViewAllowed;
    }

    void setViewAccess(boolean isViewAllowed) {
      this.isViewAllowed = isViewAllowed;
    }
  }

  /**
   * Validates if current user can view the job.
   * If user is not authorized to view the job, this method will modify the
   * response and forwards to an error page and returns Job with
   * viewJobAccess flag set to false.
   * @return JobWithViewAccessCheck object(contains JobInProgress object and
   *         viewJobAccess flag). Callers of this method will check the flag
   *         and decide if view should be allowed or not. Job will be null if
   *         the job with given jobid doesnot exist at the JobTracker.
   */
  public static JobWithViewAccessCheck checkAccessAndGetJob(final JobTracker jt,
      JobID jobid, HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    final JobInProgress job = jt.getJob(jobid);
    JobWithViewAccessCheck myJob = new JobWithViewAccessCheck(job);

    String user = request.getRemoteUser();
    if (user != null && job != null && jt.areACLsEnabled()) {
      final UserGroupInformation ugi =
        UserGroupInformation.createRemoteUser(user);
      try {
        ugi.doAs(new PrivilegedExceptionAction<Void>() {
          public Void run() throws IOException, ServletException {

            // checks job view permission
            jt.getACLsManager().checkAccess(job, ugi,
                Operation.VIEW_JOB_DETAILS);
            return null;
          }
        });
      } catch (AccessControlException e) {
        String errMsg = "User " + ugi.getShortUserName() +
            " failed to view " + jobid + "!<br><br>" + e.getMessage() +
            "<hr><a href=\"jobtracker.jsp\">Go back to JobTracker</a><br>";
        JSPUtil.setErrorAndForward(errMsg, request, response);
        myJob.setViewAccess(false);
      } catch (InterruptedException e) {
        String errMsg = " Interrupted while trying to access " + jobid +
        "<hr><a href=\"jobtracker.jsp\">Go back to JobTracker</a><br>";
        JSPUtil.setErrorAndForward(errMsg, request, response);
        myJob.setViewAccess(false);
      }
    }
    return myJob;
  }

  /**
   * Sets error code SC_UNAUTHORIZED in response and forwards to
   * error page which contains error message and a back link.
   */
  public static void setErrorAndForward(String errMsg,
      HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.setAttribute("error.msg", errMsg);
    RequestDispatcher dispatcher = request.getRequestDispatcher(
        "/job_authorization_error.jsp");
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    dispatcher.forward(request, response);
  }

  /**
   * Method used to process the request from the job page based on the 
   * request which it has received. For example like changing priority.
   * 
   * @param request HTTP request Object.
   * @param response HTTP response object.
   * @param tracker {@link JobTracker} instance
   * @throws IOException
   * @throws InterruptedException 
   * @throws ServletException 
   */
  public static void processButtons(HttpServletRequest request,
      HttpServletResponse response, final JobTracker tracker)
      throws IOException, InterruptedException, ServletException {

	String user = request.getRemoteUser();
    if (privateActionsAllowed(tracker.conf)
        && request.getParameter("killJobs") != null) {
        String[] jobs = request.getParameterValues("jobCheckBox");
        if (jobs != null) {
          boolean notAuthorized = false;
          String errMsg = "User " + user
              + " failed to kill the following job(s)!<br><br>";
          for (String job : jobs) {
            final JobID jobId = JobID.forName(job);
            if (user != null) {
              UserGroupInformation ugi =
                UserGroupInformation.createRemoteUser(user);
              try {
                ugi.doAs(new PrivilegedExceptionAction<Void>() {
                  public Void run() throws IOException{

                    tracker.killJob(jobId);// checks job modify permission
                    return null;
                  }
                });
              } catch(AccessControlException e) {
                errMsg = errMsg.concat("<br>" + e.getMessage());
                notAuthorized = true;
                // We don't return right away so that we can try killing other
                // jobs that are requested to be killed.
                continue;
              }
            }
            else {// no authorization needed
              tracker.killJob(jobId);
            }
          }
          if (notAuthorized) {// user is not authorized to kill some/all of jobs
            errMsg = errMsg.concat(
              "<br><hr><a href=\"jobtracker.jsp\">Go back to JobTracker</a><br>");
            setErrorAndForward(errMsg, request, response);
            return;
          }
        }
      }

    if (privateActionsAllowed(tracker.conf) && 
          request.getParameter("changeJobPriority") != null) {
        String[] jobs = request.getParameterValues("jobCheckBox");
        if (jobs != null) {
          final JobPriority jobPri = JobPriority.valueOf(request
              .getParameter("setJobPriority"));
          boolean notAuthorized = false;
          String errMsg = "User " + user
              + " failed to set priority for the following job(s)!<br><br>";

          for (String job : jobs) {
            final JobID jobId = JobID.forName(job);
            if (user != null) {
              UserGroupInformation ugi = UserGroupInformation.
                  createRemoteUser(user);
              try {
                ugi.doAs(new PrivilegedExceptionAction<Void>() {
                  public Void run() throws IOException{

                    // checks job modify permission
                    tracker.setJobPriority(jobId, jobPri);
                    return null;
                  }
                });
              } catch(AccessControlException e) {
                errMsg = errMsg.concat("<br>" + e.getMessage());
                notAuthorized = true;
                // We don't return right away so that we can try operating on
                // other jobs.
                continue;
              }
            }
            else {// no authorization needed
              tracker.setJobPriority(jobId, jobPri);
            }
          }
          if (notAuthorized) {// user is not authorized to kill some/all of jobs
            errMsg = errMsg.concat(
              "<br><hr><a href=\"jobtracker.jsp\">Go back to JobTracker</a><br>");
            setErrorAndForward(errMsg, request, response);
            return;
          }
        }
      }
  }

  /**
   * Method used to generate the Job table for Job pages.
   * 
   * @param label display heading to be used in the job table.
   * @param jobs vector of jobs to be displayed in table.
   * @param refresh refresh interval to be used in jobdetails page.
   * @param rowId beginning row id to be used in the table.
   * @return
   * @throws IOException
   */
  public static String generateJobTable(String label, Collection<JobInProgress> jobs
      , int refresh, int rowId, JobConf conf) throws IOException {

    boolean isModifiable = label.equals("Running") 
                                && privateActionsAllowed(conf);
    StringBuffer sb = new StringBuffer();
    sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" class=\"sortable\">\n");

    if (jobs.size() > 0) {
      if (isModifiable) {
        sb.append("<form action=\"/jobtracker.jsp\" onsubmit=\"return confirmAction();\" method=\"POST\">");
        sb.append("<tr>");
        sb.append("<td><input type=\"Button\" onclick=\"selectAll()\" " +
        		"value=\"Select All\" id=\"checkEm\"></td>");
        sb.append("<td>");
        sb.append("<input type=\"submit\" name=\"killJobs\" value=\"Kill Selected Jobs\">");
        sb.append("</td");
        sb.append("<td><nobr>");
        sb.append("<select name=\"setJobPriority\">");

        for (JobPriority prio : JobPriority.values()) {
          sb.append("<option"
              + (JobPriority.NORMAL == prio ? " selected=\"selected\">" : ">")
              + prio + "</option>");
        }

        sb.append("</select>");
        sb.append("<input type=\"submit\" name=\"changeJobPriority\" " +
        		"value=\"Change\">");
        sb.append("</nobr></td>");
        sb.append("<td colspan=\"10\">&nbsp;</td>");
        sb.append("</tr>");
        sb.append("<td>&nbsp;</td>");
      } else {
        sb.append("<tr>");
      }

      sb.append("<td><b>Jobid</b></td><td><b>Priority" +
      		"</b></td><td><b>User</b></td>");
      sb.append("<td><b>Name</b></td>");
      sb.append("<td><b>Map % Complete</b></td>");
      sb.append("<td><b>Map Total</b></td>");
      sb.append("<td><b>Maps Completed</b></td>");
      sb.append("<td><b>Reduce % Complete</b></td>");
      sb.append("<td><b>Reduce Total</b></td>");
      sb.append("<td><b>Reduces Completed</b></td>");
      sb.append("<td><b>Job Scheduling Information</b></td>");
      sb.append("<td><b>Diagnostic Info </b></td>");
      sb.append("</tr>\n");

      for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext(); ++rowId) {
        JobInProgress job = it.next();
        JobProfile profile = job.getProfile();
        JobStatus status = job.getStatus();
        JobID jobid = profile.getJobID();

        int desiredMaps = job.desiredMaps();
        int desiredReduces = job.desiredReduces();
        int completedMaps = job.finishedMaps();
        int completedReduces = job.finishedReduces();
        String name = HtmlQuoting.quoteHtmlChars(profile.getJobName());
        String jobpri = job.getPriority().toString();
        String schedulingInfo =
          HtmlQuoting.quoteHtmlChars(job.getStatus().getSchedulingInfo());
        String diagnosticInfo = 
          HtmlQuoting.quoteHtmlChars(job.getStatus().getFailureInfo());
        if (isModifiable) {
          sb.append("<tr><td><input TYPE=\"checkbox\" " +
          		"onclick=\"checkButtonVerbage()\" " +
          		"name=\"jobCheckBox\" value="
                  + jobid + "></td>");
        } else {
          sb.append("<tr>");
        }

        sb.append("<td id=\"job_" + rowId
            + "\"><a href=\"jobdetails.jsp?jobid=" + jobid + "&refresh="
            + refresh + "\">" + jobid + "</a></td>" + "<td id=\"priority_"
            + rowId + "\">" + jobpri + "</td>" + "<td id=\"user_" + rowId
            + "\">" + HtmlQuoting.quoteHtmlChars(profile.getUser()) +
              "</td>" + "<td id=\"name_" + rowId
            + "\">" + ("".equals(name) ? "&nbsp;" : name) + "</td>" + "<td>"
            + StringUtils.formatPercent(status.mapProgress(), 2)
            + ServletUtil.percentageGraph(status.mapProgress() * 100, 80)
            + "</td><td>" + desiredMaps + "</td><td>" + completedMaps
            + "</td><td>"
            + StringUtils.formatPercent(status.reduceProgress(), 2)
            + ServletUtil.percentageGraph(status.reduceProgress() * 100, 80)
            + "</td><td>" + desiredReduces + "</td><td> " + completedReduces 
            + "</td><td>" + schedulingInfo
            + "</td><td>" + diagnosticInfo + "</td></tr>\n");
      }
      if (isModifiable) {
        sb.append("</form>\n");
      }
    } else {
      sb.append("<tr><td align=\"center\" colspan=\"8\"><i>none</i>" +
      		"</td></tr>\n");
    }
    sb.append("</table>\n");
    
    return sb.toString();
  }

  @SuppressWarnings("unchecked")
  public static String generateRetiredJobTable(JobTracker tracker, int rowId) 
    throws IOException {

    StringBuffer sb = new StringBuffer();
    sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");

    Iterator<RetireJobInfo> iterator = 
      tracker.retireJobs.getAll().descendingIterator();
    if (!iterator.hasNext()) {
      sb.append("<tr><td align=\"center\" colspan=\"8\"><i>none</i>" +
      "</td></tr>\n");
    } else {
      sb.append("<tr>");
      
      sb.append("<td><b>Jobid</b></td>");
      sb.append("<td><b>Priority</b></td>");
      sb.append("<td><b>User</b></td>");
      sb.append("<td><b>Name</b></td>");
      sb.append("<td><b>State</b></td>");
      sb.append("<td><b>Start Time</b></td>");
      sb.append("<td><b>Finish Time</b></td>");
      sb.append("<td><b>Map % Complete</b></td>");
      sb.append("<td><b>Reduce % Complete</b></td>");
      sb.append("<td><b>Job Scheduling Information</b></td>");
      sb.append("<td><b>Diagnostic Info </b></td>");
      sb.append("</tr>\n");
      for (int i = 0; i < 100 && iterator.hasNext(); i++) {
        RetireJobInfo info = iterator.next();
        String historyFile = info.getHistoryFile();
        String historyFileUrl = null;
        if (historyFile != null && !historyFile.equals("")) {
          try {
            historyFileUrl = URLEncoder.encode(info.getHistoryFile(), "UTF-8");
          } catch (UnsupportedEncodingException e) {
            LOG.warn("Can't create history url ", e);
          }
        }
        sb.append("<tr>");
        sb.append(
            "<td id=\"job_" + rowId + "\">" + 
            
              (historyFileUrl == null ? "" :
              "<a href=\"" + JobHistoryServer.getHistoryUrlPrefix(tracker.conf) +
                  "/jobdetailshistory.jsp?logFile=" + historyFileUrl + "\">") +
              
              info.status.getJobId() + "</a></td>" +
            
            "<td id=\"priority_" + rowId + "\">" + 
              info.status.getJobPriority().toString() + "</td>" +
            "<td id=\"user_" + rowId + "\">" +
              HtmlQuoting.quoteHtmlChars(info.profile.getUser()) + "</td>" +
            "<td id=\"name_" + rowId + "\">" +
              HtmlQuoting.quoteHtmlChars(info.profile.getJobName()) + "</td>" +
            "<td>" + JobStatus.getJobRunState(info.status.getRunState()) 
              + "</td>" +
            "<td>" + new Date(info.status.getStartTime()) + "</td>" +
            "<td>" + new Date(info.finishTime) + "</td>" +
            
            "<td>" + StringUtils.formatPercent(info.status.mapProgress(), 2)
            + ServletUtil.percentageGraph(info.status.mapProgress() * 100, 80) + 
              "</td>" +
            
            "<td>" + StringUtils.formatPercent(info.status.reduceProgress(), 2)
            + ServletUtil.percentageGraph(
               info.status.reduceProgress() * 100, 80) + 
              "</td>" +
            
            "<td>" +
            HtmlQuoting.quoteHtmlChars(info.status.getSchedulingInfo()) +
            "</td>" + 
            "<td>" + HtmlQuoting.quoteHtmlChars(info.status.getFailureInfo()) + 
            "</td></tr>\n");
        rowId++;
      }
    }
    sb.append("</table>\n");
    return sb.toString();
  }

  static Path getJobConfFilePath(Path logFile) {
    return JobHistory.confPathFromLogFilePath(logFile);
  }

  /**
   * Read a job-history log file and construct the corresponding {@link JobInfo}
   * . Also cache the {@link JobInfo} for quick serving further requests.
   * 
   * @param logFile
   * @param fs
   * @return JobInfo
   * @throws IOException
   */
  static JobInfo getJobInfo(Path logFile, FileSystem fs,
      JobConf jobConf, ACLsManager acLsManager, String user) throws IOException {
    String jobid = getJobID(logFile.getName());
    JobInfo jobInfo = null;
    synchronized(jobHistoryCache) {
      jobInfo = jobHistoryCache.remove(jobid);
      if (jobInfo == null) {
        jobInfo = new JobHistory.JobInfo(jobid);
        LOG.info("Loading Job History file "+jobid + ".   Cache size is " +
            jobHistoryCache.size());
        DefaultJobHistoryParser.parseJobTasks(logFile.toUri().getPath(),
            jobInfo, fs);
      }
      jobHistoryCache.put(jobid, jobInfo);
      int CACHE_SIZE = 
        jobConf.getInt("mapred.job.tracker.jobhistory.lru.cache.size", 5);
      if (jobHistoryCache.size() > CACHE_SIZE) {
        Iterator<Map.Entry<String, JobInfo>> it = 
          jobHistoryCache.entrySet().iterator();
        String removeJobId = it.next().getKey();
        it.remove();
        LOG.info("Job History file removed form cache "+removeJobId);
      }
    }

    UserGroupInformation currentUser;
    if (user == null) {
      currentUser = UserGroupInformation.getCurrentUser();
    } else {
      currentUser = UserGroupInformation.createRemoteUser(user);
    }

    // Authorize the user for view access of this job
    acLsManager.checkAccess(jobid, currentUser,
        jobInfo.getJobQueue(), Operation.VIEW_JOB_DETAILS,
        jobInfo.get(Keys.USER), jobInfo.getJobACLs().get(JobACL.VIEW_JOB));

    return jobInfo;
  }

  /**
   * Check the access for users to view job-history pages.
   * 
   * @param request
   * @param response
   * @param fs
   * @param logFile
   * @return the job if authorization is disabled or if the authorization checks
   *         pass. Otherwise return null.
   * @throws IOException
   * @throws InterruptedException
   * @throws ServletException
   */
  static JobInfo checkAccessAndGetJobInfo(HttpServletRequest request,
      HttpServletResponse response, final JobConf jobConf,
      final ACLsManager acLsManager, final FileSystem fs,
      final Path logFile) throws IOException,
      InterruptedException, ServletException {
    String jobid = getJobID(logFile.getName());
    String user = request.getRemoteUser();
    JobInfo job = null;
    if (user != null) {
      try {
        job = JSPUtil.getJobInfo(logFile, fs, jobConf, acLsManager, user);
      } catch (AccessControlException e) {
        String trackerAddress = jobConf.get("mapred.job.tracker.http.address");
        String errMsg =
            String.format(
                "User %s failed to view %s!<br><br>%s"
                    + "<hr>"
                    + "<a href=\"jobhistory.jsp\">Go back to JobHistory</a><br>"
                    + "<a href=\"http://" + trackerAddress +
                    "/jobtracker.jsp\">Go back to JobTracker</a>",
                user, jobid, e.getMessage());
        JSPUtil.setErrorAndForward(errMsg, request, response);
        return null;
      }
    } else {
      // no authorization needed
      job = JSPUtil.getJobInfo(logFile, fs, jobConf, acLsManager, null);
    }
    return job;
  }

  static String getJobID(String historyFileName) {
    return JobHistory.jobIdNameFromLogFileName(historyFileName);
  }

  static String getUserName(String historyFileName) {
    return JobHistory.userNameFromLogFileName(historyFileName);
  }

  static String getJobName(String historyFileName) {
    return JobHistory.jobNameFromLogFileName(historyFileName);
  }

  /**
   * Nicely print the Job-ACLs
   * @param tracker
   * @param jobAcls
   * @param out
   * @throws IOException
   */
  static void printJobACLs(JobTracker tracker,
      Map<JobACL, AccessControlList> jobAcls, JspWriter out)
      throws IOException {
    if (tracker.areACLsEnabled()) {
      printJobACLsInternal(jobAcls, out);
    }
    else {
      out.print("<b>Job-ACLs: " + new AccessControlList("*").toString()
          + "</b><br>");
    }
  }

  static void printJobACLs(JobConf conf,
      Map<JobACL, AccessControlList> jobAcls, JspWriter out)
      throws IOException {
    if (conf.getBoolean(JobConf.MR_ACLS_ENABLED, false)) {
      printJobACLsInternal(jobAcls, out);
    }
    else {
      out.print("<b>Job-ACLs: " + new AccessControlList("*").toString()
          + "</b><br>");
    }
  }

  private static void printJobACLsInternal(Map<JobACL, AccessControlList> jobAcls,
                                           JspWriter out) throws IOException {
    // Display job-view-acls and job-modify-acls configured for this job
    out.print("<b>Job-ACLs:</b><br>");
    for (JobACL aclName : JobACL.values()) {
      String aclConfigName = aclName.getAclName();
      AccessControlList aclConfigured = jobAcls.get(aclName);
      if (aclConfigured != null) {
        String aclStr = aclConfigured.toString();
        out.print("&nbsp;&nbsp;&nbsp;&nbsp;" + aclConfigName + ": "
            + aclStr + "<br>");
      }
    }
  }

  static boolean privateActionsAllowed(JobConf conf) {
    return conf.getBoolean(PRIVATE_ACTIONS_KEY, false);
  }
}
