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; 034import org.apache.oozie.ErrorCode; 035import org.apache.oozie.SLAEventBean; 036import org.apache.oozie.client.OozieClient; 037import org.apache.oozie.client.rest.RestConstants; 038import org.apache.oozie.command.CommandException; 039import org.apache.oozie.command.coord.SLAEventsXCommand; 040import org.apache.oozie.util.XLog; 041import org.apache.oozie.util.XmlUtils; 042import org.jdom.Element; 043 044@SuppressWarnings("deprecation") 045public class SLAServlet extends JsonRestServlet { 046 047 private static final Set<String> SLA_FILTER_NAMES = new HashSet<String>(); 048 049 static { 050 SLA_FILTER_NAMES.add(OozieClient.FILTER_JOBID); 051 SLA_FILTER_NAMES.add(OozieClient.FILTER_APPNAME); 052 } 053 054 private static final String INSTRUMENTATION_NAME = "sla"; 055 056 private static final JsonRestServlet.ResourceInfo RESOURCES_INFO[] = new JsonRestServlet.ResourceInfo[1]; 057 058 static { 059 RESOURCES_INFO[0] = new JsonRestServlet.ResourceInfo("", Arrays.asList("GET"), Arrays.asList( 060 new JsonRestServlet.ParameterInfo(RestConstants.SLA_GT_SEQUENCE_ID, String.class, false, Arrays 061 .asList("GET")), new JsonRestServlet.ParameterInfo(RestConstants.MAX_EVENTS, String.class, 062 false, Arrays.asList("GET")), new JsonRestServlet.ParameterInfo( 063 RestConstants.JOBS_FILTER_PARAM, String.class, false, Arrays.asList("GET")))); 064 } 065 066 public SLAServlet() { 067 super(INSTRUMENTATION_NAME, RESOURCES_INFO); 068 } 069 070 public SLAServlet(String instrumentationName, ResourceInfo... resourcesInfo) { 071 super(instrumentationName, resourcesInfo); 072 } 073 074 /** 075 * Return information about SLA Events. 076 */ 077 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 078 079 Element eResponse = new Element("sla-message"); 080 List<SLAEventBean> slaEvntList = null; 081 082 try { 083 stopCron(); 084 String gtSequenceNum = request.getParameter(RestConstants.SLA_GT_SEQUENCE_ID); 085 String strMaxEvents = request.getParameter(RestConstants.MAX_EVENTS); 086 String filter = request.getParameter(RestConstants.JOBS_FILTER_PARAM); 087 Map<String, List<String>> filterList = parseFilter(filter, SLA_FILTER_NAMES); 088 089 int maxNoEvents = 100; // Default 090 XLog.getLog(getClass()).debug( 091 "Got SLA GET request for :" + gtSequenceNum + " and max-events :" + strMaxEvents); 092 if (strMaxEvents != null && strMaxEvents.length() > 0) { 093 maxNoEvents = Integer.parseInt(strMaxEvents); 094 } 095 096 if (gtSequenceNum != null) { 097 long seqId = Long.parseLong(gtSequenceNum); 098 stopCron(); 099 SLAEventsXCommand seCommand = new SLAEventsXCommand(seqId, maxNoEvents, filterList); 100 slaEvntList = seCommand.call(); 101 long lastSeqId = seCommand.getLastSeqId(); 102 103 eResponse = new Element("sla-message"); 104 for (SLAEventBean event : slaEvntList) { 105 eResponse.addContent(event.toXml()); 106 } 107 Element eLastSeq = new Element("last-sequence-id"); 108 eLastSeq.addContent(String.valueOf(lastSeqId)); 109 eResponse.addContent(eLastSeq); 110 XLog.getLog(getClass()).debug("Writing back SLA Servlet Caller with last-seq-id " + lastSeqId); 111 startCron(); 112 } 113 else { 114 XLog.getLog(getClass()).error("gt-sequence-id parameter is not specified in the http request"); 115 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 116 "gt-sequence-id parameter is not specified in the http request"); 117 } 118 startCron(); 119 response.setContentType(XML_UTF8); 120 response.setStatus(HttpServletResponse.SC_OK); 121 response.getWriter().write(XmlUtils.prettyPrint(eResponse) + "\n"); 122 } 123 catch (CommandException ce) { 124 ce.printStackTrace(); 125 XLog.getLog(getClass()).error("Command exception ", ce); 126 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ce); 127 } 128 catch (RuntimeException re) { 129 re.printStackTrace(); 130 XLog.getLog(getClass()).error("Runtime error ", re); 131 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0307, re.getMessage()); 132 } 133 } 134 135 protected Map<String, List<String>> parseFilter(String filterString, Set<String> allowedFilters) throws ServletException { 136 Map<String, List<String>> map = new HashMap<String, List<String>>(); 137 if (filterString != null) { 138 StringTokenizer st = new StringTokenizer(filterString, ";"); 139 while (st.hasMoreTokens()) { 140 String token = st.nextToken(); 141 if (token.contains("=")) { 142 String[] pair = token.split("="); 143 if (pair.length != 2) { 144 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 145 "elements must be semicolon-separated name=value pairs"); 146 } 147 if (!allowedFilters.contains(pair[0])) { 148 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 149 "invalid/unsupported names in filter"); 150 } 151 List<String> list = map.get(pair[0]); 152 if (list == null) { 153 list = new ArrayList<String>(); 154 map.put(pair[0], list); 155 } 156 list.add(pair[1]); 157 } 158 else { 159 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401, 160 "elements must be semicolon-separated name=value pairs"); 161 } 162 } 163 } 164 return map; 165 } 166 167}