azkaban.web.pages.IndexServlet.java Source code

Java tutorial

Introduction

Here is the source code for azkaban.web.pages.IndexServlet.java

Source

/*
 * Copyright 2010 LinkedIn, Inc
 * 
 * Licensed 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 azkaban.web.pages;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Hours;
import org.joda.time.LocalDateTime;
import org.joda.time.Minutes;
import org.joda.time.ReadablePeriod;
import org.joda.time.Seconds;
import org.joda.time.format.DateTimeFormat;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import azkaban.app.AzkabanApplication;
import azkaban.app.JobDescriptor;
import azkaban.app.JobManager;
import azkaban.common.web.Page;
import azkaban.flow.ExecutableFlow;
import azkaban.flow.Flow;
import azkaban.flow.FlowManager;
import azkaban.jobs.JobExecutionException;
import azkaban.jobs.JobExecutorManager.ExecutingJobAndInstance;
import azkaban.util.json.JSONUtils;
import azkaban.web.AbstractAzkabanServlet;

/**
 * The main page
 * 
 * @author jkreps
 * 
 */
public class IndexServlet extends AbstractAzkabanServlet {

    private static final Logger logger = Logger.getLogger(IndexServlet.class.getName());

    private static final long serialVersionUID = 1;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /* set runtime properties from request and response */
        super.setRuntimeProperties(req, resp);

        AzkabanApplication app = getApplication();
        @SuppressWarnings("unused")
        Map<String, JobDescriptor> descriptors = app.getJobManager().loadJobDescriptors();
        Page page = newPage(req, resp, "azkaban/web/pages/index.vm");
        page.add("logDir", app.getLogDirectory());
        page.add("flows", app.getAllFlows());
        page.add("scheduled", app.getScheduleManager().getSchedule());
        page.add("executing", app.getJobExecutorManager().getExecutingJobs());
        page.add("completed", app.getJobExecutorManager().getCompleted());
        page.add("rootJobNames", app.getAllFlows().getRootFlowNames());
        page.add("folderNames", app.getAllFlows().getFolders());
        page.add("jobDescComparator", JobDescriptor.NAME_COMPARATOR);
        page.render();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        /* set runtime properties from request and response */
        super.setRuntimeProperties(req, resp);

        AzkabanApplication app = getApplication();
        String action = getParam(req, "action");
        if ("loadjobs".equals(action)) {
            resp.setContentType("application/json");
            String folder = getParam(req, "folder");
            resp.getWriter().print(getJSONJobsForFolder(app.getAllFlows(), folder));
            resp.getWriter().flush();
            return;
        } else if ("unschedule".equals(action)) {
            String jobid = getParam(req, "job");
            app.getScheduleManager().removeScheduledJob(jobid);
        } else if ("cancel".equals(action)) {
            cancelJob(app, req);
        } else if ("schedule".equals(action)) {
            String redirect = scheduleJobs(app, req, resp);
            if (!redirect.isEmpty()) {
                resp.sendRedirect(redirect);
                return;
            }
        } else {
            throw new ServletException("Unknown action: " + action);
        }
        resp.sendRedirect(req.getContextPath());
    }

    @SuppressWarnings("unchecked")
    private String getJSONJobsForFolder(FlowManager manager, String folder) {
        List<String> rootJobs = manager.getRootNamesByFolder(folder);
        Collections.sort(rootJobs);

        JSONArray rootJobObj = new JSONArray();
        for (String root : rootJobs) {
            Flow flow = manager.getFlow(root);
            JSONObject flowObj = getJSONDependencyTree(flow);
            rootJobObj.add(flowObj);
        }

        return rootJobObj.toJSONString();
    }

    @SuppressWarnings("unchecked")
    private JSONObject getJSONDependencyTree(Flow flow) {
        JSONObject jobObject = new JSONObject();
        jobObject.put("name", flow.getName());

        if (flow.hasChildren()) {
            JSONArray dependencies = new JSONArray();
            for (Flow child : flow.getChildren()) {
                JSONObject childObj = getJSONDependencyTree(child);
                dependencies.add(childObj);
            }

            Collections.sort(dependencies, new FlowComparator());
            jobObject.put("dep", dependencies);
        }

        return jobObject;
    }

    private class FlowComparator implements Comparator<JSONObject> {

        @Override
        public int compare(JSONObject arg0, JSONObject arg1) {
            String first = (String) arg0.get("name");
            String second = (String) arg1.get("name");
            return first.compareTo(second);
        }

    }

    private void cancelJob(AzkabanApplication app, HttpServletRequest req) throws ServletException {

        String jobId = getParam(req, "job");
        try {
            app.getJobExecutorManager().cancel(jobId);
        } catch (Exception e1) {
            logger.error("Error cancelling job " + e1);
        }

        Collection<ExecutingJobAndInstance> executing = app.getJobExecutorManager().getExecutingJobs();
        for (ExecutingJobAndInstance curr : executing) {
            ExecutableFlow flow = curr.getExecutableFlow();
            final String flowId = flow.getId();
            if (flowId.equals(jobId)) {
                final String flowName = flow.getName();
                try {
                    if (flow.cancel()) {
                        addMessage(req, "Cancelled " + flowName);
                        logger.info("Job '" + flowName + "' cancelled from gui.");
                    } else {
                        logger.info("Couldn't cancel flow '" + flowName + "' for some reason.");
                        addError(req, "Failed to cancel flow " + flowName + ".");
                    }
                } catch (Exception e) {
                    logger.error("Exception while attempting to cancel flow '" + flowName + "'.", e);
                    addError(req, "Failed to cancel flow " + flowName + ": " + e.getMessage());
                }
            }
        }
    }

    private String scheduleJobs(AzkabanApplication app, HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        String[] jobNames = req.getParameterValues("jobs");
        if (!hasParam(req, "jobs")) {
            addError(req, "You must select at least one job to run.");
            return "";
        }

        if (hasParam(req, "flow_now")) {
            if (jobNames.length > 1) {
                addError(req, "Can only run flow instance on one job.");
                return "";
            }

            String jobName = jobNames[0];
            JobManager jobManager = app.getJobManager();
            JobDescriptor descriptor = jobManager.getJobDescriptor(jobName);
            if (descriptor == null) {
                addError(req, "Can only run flow instance on one job.");
                return "";
            } else {
                return req.getContextPath() + "/flow?job_id=" + jobName;
            }
        } else {
            for (String job : jobNames) {
                if (hasParam(req, "schedule")) {
                    int hour = getIntParam(req, "hour");
                    int minutes = getIntParam(req, "minutes");
                    boolean isPm = getParam(req, "am_pm").equalsIgnoreCase("pm");
                    String scheduledDate = req.getParameter("date");
                    DateTime day = null;
                    if (scheduledDate == null || scheduledDate.trim().length() == 0) {
                        day = new LocalDateTime().toDateTime();
                    } else {
                        try {
                            day = DateTimeFormat.forPattern("MM-dd-yyyy").parseDateTime(scheduledDate);
                        } catch (IllegalArgumentException e) {
                            addError(req, "Invalid date: '" + scheduledDate + "'");
                            return "";
                        }
                    }

                    ReadablePeriod thePeriod = null;
                    if (hasParam(req, "is_recurring"))
                        thePeriod = parsePeriod(req);

                    if (isPm && hour < 12)
                        hour += 12;
                    hour %= 24;

                    app.getScheduleManager().schedule(job,
                            day.withHourOfDay(hour).withMinuteOfHour(minutes).withSecondOfMinute(0), thePeriod,
                            false);

                    addMessage(req, job + " scheduled.");
                } else if (hasParam(req, "schedule_trigger")) {
                    String topic = getParam(req, "topic");

                    HashMap<String, String> criteria = new HashMap<String, String>();

                    for (int i = 0;; i++) {
                        String key = req.getParameter("key" + i);
                        String val = req.getParameter("val" + i);
                        if (key == null || val == null)
                            break;
                        if (key.length() > 0)
                            criteria.put(key, val);
                    }

                    String group = getParam(req, "group_id");
                    int startHour = getIntParam(req, "start_hour");
                    boolean startIsPm = getParam(req, "start_am_pm").equalsIgnoreCase("pm");
                    int stopHour = getIntParam(req, "stop_hour");
                    if (startIsPm) {
                        startHour += 12;
                        startHour %= 24;
                    }
                    boolean stopIsPm = getParam(req, "stop_am_pm").equalsIgnoreCase("pm");
                    if (stopIsPm) {
                        stopHour += 12;
                        stopHour %= 24;
                    }

                    app.getScheduleManager().schedule(job, topic, criteria, group, startHour, stopHour, false); //with dependencies.

                    addMessage(req, topic + " scheduled.");

                } else if (hasParam(req, "run_now")) {
                    boolean ignoreDeps = !hasParam(req, "include_deps");
                    try {
                        app.getJobExecutorManager().execute(job, ignoreDeps);
                    } catch (JobExecutionException e) {
                        addError(req, e.getMessage());
                        return "";
                    }
                    addMessage(req, "Running " + job);
                } else {
                    addError(req, "Neither run_now nor schedule param is set.");
                }
            }
            return "";
        }

    }

    private ReadablePeriod parsePeriod(HttpServletRequest req) throws ServletException {
        int period = getIntParam(req, "period");
        String periodUnits = getParam(req, "period_units");
        if ("d".equals(periodUnits))
            return Days.days(period);
        else if ("h".equals(periodUnits))
            return Hours.hours(period);
        else if ("m".equals(periodUnits))
            return Minutes.minutes(period);
        else if ("s".equals(periodUnits))
            return Seconds.seconds(period);
        else
            throw new ServletException("Unknown period unit: " + periodUnits);
    }

}