Java tutorial
/* * 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); } }