001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.oozie.servlet; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.StringTokenizer; 030 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServletRequest; 033import javax.servlet.http.HttpServletResponse; 034 035import org.apache.oozie.ErrorCode; 036import org.apache.oozie.SLAEventBean; 037import org.apache.oozie.client.OozieClient; 038import org.apache.oozie.client.rest.RestConstants; 039import org.apache.oozie.command.CommandException; 040import org.apache.oozie.command.coord.SLAEventsXCommand; 041import org.apache.oozie.util.XLog; 042import org.apache.oozie.util.XmlUtils; 043import org.jdom.Element; 044 045@SuppressWarnings("deprecation") 046public class SLAServlet extends JsonRestServlet { 047 048 private static final Set<String> SLA_FILTER_NAMES = new HashSet<String>(); 049 050 static { 051 SLA_FILTER_NAMES.add(OozieClient.FILTER_JOBID); 052 SLA_FILTER_NAMES.add(OozieClient.FILTER_APPNAME); 053 } 054 055 private static final String INSTRUMENTATION_NAME = "sla"; 056 057 private static final JsonRestServlet.ResourceInfo RESOURCES_INFO[] = new JsonRestServlet.ResourceInfo[1]; 058 059 static { 060 RESOURCES_INFO[0] = new JsonRestServlet.ResourceInfo("", Arrays.asList("GET"), Arrays.asList( 061 new JsonRestServlet.ParameterInfo(RestConstants.SLA_GT_SEQUENCE_ID, String.class, false, Arrays 062 .asList("GET")), new JsonRestServlet.ParameterInfo(RestConstants.MAX_EVENTS, String.class, 063 false, Arrays.asList("GET")), new JsonRestServlet.ParameterInfo( 064 RestConstants.JOBS_FILTER_PARAM, String.class, false, Arrays.asList("GET")))); 065 } 066 067 public SLAServlet() { 068 super(INSTRUMENTATION_NAME, RESOURCES_INFO); 069 } 070 071 public SLAServlet(String instrumentationName, ResourceInfo... resourcesInfo) { 072 super(instrumentationName, resourcesInfo); 073 } 074 075 /** 076 * Return information about SLA Events. 077 */ 078 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 079 080 Element eResponse = new Element("sla-message"); 081 List<SLAEventBean> slaEvntList = null; 082 083 try { 084 stopCron(); 085 String gtSequenceNum = request.getParameter(RestConstants.SLA_GT_SEQUENCE_ID); 086 String strMaxEvents = request.getParameter(RestConstants.MAX_EVENTS); 087 String filter = request.getParameter(RestConstants.JOBS_FILTER_PARAM); 088 Map<String, List<String>> filterList = parseFilter(filter, SLA_FILTER_NAMES); 089 090 int maxNoEvents = 100; // Default 091 XLog.getLog(getClass()).debug( 092 "Got SLA GET request for :" + gtSequenceNum + " and max-events :" + strMaxEvents); 093 if (strMaxEvents != null && strMaxEvents.length() > 0) { 094 maxNoEvents = Integer.parseInt(strMaxEvents); 095 } 096 097 if (gtSequenceNum != null) { 098 long seqId = Long.parseLong(gtSequenceNum); 099 stopCron(); 100 SLAEventsXCommand seCommand = new SLAEventsXCommand(seqId, maxNoEvents, filterList); 101 slaEvntList = seCommand.call(); 102 long lastSeqId = seCommand.getLastSeqId(); 103 104 eResponse = new Element("sla-message"); 105 for (SLAEventBean event : slaEvntList) { 106 eResponse.addContent(event.toXml()); 107 } 108 Element eLastSeq = new Element("last-sequence-id"); 109 eLastSeq.addContent(String.valueOf(lastSeqId)); 110 eResponse.addContent(eLastSeq); 111 XLog.getLog(getClass()).debug("Writing back SLA Servlet Caller with last-seq-id " + lastSeqId); 112 startCron(); 113 } 114 else { 115 XLog.getLog(getClass()).error("gt-sequence-id parameter is not specified in the http request"); 116 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 117 "gt-sequence-id parameter is not specified in the http request"); 118 } 119 startCron(); 120 response.setContentType(XML_UTF8); 121 response.setStatus(HttpServletResponse.SC_OK); 122 response.getWriter().write(XmlUtils.prettyPrint(eResponse) + "\n"); 123 } 124 catch (CommandException ce) { 125 ce.printStackTrace(); 126 XLog.getLog(getClass()).error("Command exception ", ce); 127 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ce); 128 } 129 catch (RuntimeException re) { 130 re.printStackTrace(); 131 XLog.getLog(getClass()).error("Runtime error ", re); 132 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0307, re.getMessage()); 133 } 134 } 135 136 protected Map<String, List<String>> parseFilter(String filterString, Set<String> allowedFilters) throws ServletException { 137 Map<String, List<String>> map = new HashMap<String, List<String>>(); 138 if (filterString != null) { 139 StringTokenizer st = new StringTokenizer(filterString, ";"); 140 while (st.hasMoreTokens()) { 141 String token = st.nextToken(); 142 if (token.contains("=")) { 143 String[] pair = token.split("="); 144 if (pair.length != 2) { 145 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 146 "elements must be semicolon-separated name=value pairs"); 147 } 148 if (!allowedFilters.contains(pair[0])) { 149 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 150 "invalid/unsupported names in filter"); 151 } 152 List<String> list = map.get(pair[0]); 153 if (list == null) { 154 list = new ArrayList<String>(); 155 map.put(pair[0], list); 156 } 157 list.add(pair[1]); 158 } 159 else { 160 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 161 "elements must be semicolon-separated name=value pairs"); 162 } 163 } 164 } 165 return map; 166 } 167 168}