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.executor.jpa.sla; 020 021import java.sql.Timestamp; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Date; 025import java.util.LinkedHashMap; 026import java.util.List; 027import java.util.Map; 028 029import javax.persistence.EntityManager; 030import javax.persistence.Query; 031 032import org.apache.oozie.ErrorCode; 033import org.apache.oozie.client.event.SLAEvent; 034import org.apache.oozie.client.event.SLAEvent.EventStatus; 035import org.apache.oozie.executor.jpa.JPAExecutor; 036import org.apache.oozie.executor.jpa.JPAExecutorException; 037import org.apache.oozie.sla.SLASummaryBean; 038 039/** 040 * Load the list of SLASummaryBean (for dashboard) and return the list. 041 */ 042public class SLASummaryGetForFilterJPAExecutor implements JPAExecutor<List<SLASummaryBean>> { 043 044 private static final String selectStr = "SELECT OBJECT(s) FROM SLASummaryBean s WHERE "; 045 046 private SLASummaryFilter filter; 047 private int numMaxResults; 048 049 050 public SLASummaryGetForFilterJPAExecutor(SLASummaryFilter filter, int numMaxResults) { 051 this.filter = filter; 052 this.numMaxResults = numMaxResults; 053 } 054 055 @Override 056 public String getName() { 057 return "SLASummaryGetForFilterJPAExecutor"; 058 } 059 060 @SuppressWarnings("unchecked") 061 @Override 062 public List<SLASummaryBean> execute(EntityManager em) throws JPAExecutorException { 063 List<SLASummaryBean> ssBean; 064 StringBuilder sb = new StringBuilder(selectStr); 065 Map<String, Object> queryParams = new LinkedHashMap<String, Object>(); 066 boolean firstCondition = true; 067 if (filter.getJobId() != null) { 068 firstCondition = false; 069 if (filter.getParentId() != null) { 070 sb.append("(s.jobId = :jobId OR s.parentId = :parentId)"); 071 queryParams.put("jobId", filter.getJobId()); 072 queryParams.put("parentId", filter.getParentId()); 073 } 074 else { 075 sb.append("s.jobId = :jobId"); 076 queryParams.put("jobId", filter.getJobId()); 077 } 078 } 079 if (filter.getParentId() != null && filter.getJobId() == null) { 080 firstCondition = false; 081 sb.append("s.parentId = :parentId"); 082 queryParams.put("parentId", filter.getParentId()); 083 } 084 if (filter.getAppName() != null && filter.getJobId() == null && filter.getParentId() == null) { 085 firstCondition = false; 086 sb.append("s.appName = :appName"); 087 queryParams.put("appName", filter.getAppName()); 088 } 089 if (filter.getNominalStart() != null) { 090 if (firstCondition) { 091 firstCondition = false; 092 } 093 else { 094 sb.append(" AND "); 095 } 096 sb.append("s.nominalTimeTS >= :nominalTimeStart"); 097 queryParams.put("nominalTimeStart", new Timestamp(filter.getNominalStart().getTime())); 098 } 099 100 if (filter.getNominalEnd() != null) { 101 if (firstCondition) { 102 firstCondition = false; 103 } 104 else { 105 sb.append(" AND "); 106 } 107 sb.append("s.nominalTimeTS <= :nominalTimeEnd"); 108 queryParams.put("nominalTimeEnd", new Timestamp(filter.getNominalEnd().getTime())); 109 } 110 111 if (filter.getEventStatus() != null) { 112 processEventStatusFilter(filter, queryParams, sb, firstCondition); 113 } 114 115 sb.append(" ORDER BY s.nominalTimeTS"); 116 try { 117 Query q = em.createQuery(sb.toString()); 118 for (Map.Entry<String, Object> entry : queryParams.entrySet()) { 119 q.setParameter(entry.getKey(), entry.getValue()); 120 } 121 q.setMaxResults(numMaxResults); 122 ssBean = (List<SLASummaryBean>) q.getResultList(); 123 } 124 catch (Exception e) { 125 throw new JPAExecutorException(ErrorCode.E0603, e.getMessage(), e); 126 } 127 return ssBean; 128 } 129 130 private void processEventStatusFilter(SLASummaryFilter filter, Map<String, Object> queryParams, StringBuilder sb, 131 boolean firstCondition) { 132 if (!firstCondition) { 133 sb.append(" AND "); 134 } 135 final List<EventStatus> eventStatuses = filter.getEventStatus(); 136 int ind = 0; 137 final Timestamp currentTime = new Timestamp(new Date().getTime()); 138 if (eventStatuses.size() > 1) { 139 sb.append("("); 140 } 141 for (EventStatus status : eventStatuses) { 142 if (ind > 0) { 143 sb.append(" OR "); 144 } 145 if (status.equals(EventStatus.START_MET)) { 146 sb.append("(s.expectedStartTS IS NOT NULL AND s.actualStartTS IS NOT NULL ").append( 147 " AND s.expectedStartTS >= s.actualStartTS)"); 148 } 149 else if (status.equals(EventStatus.START_MISS)) { 150 sb.append("((s.expectedStartTS IS NOT NULL AND s.actualStartTS IS NOT NULL ") 151 .append(" AND s.expectedStartTS <= s.actualStartTS) ") 152 .append("OR (s.expectedStartTS IS NOT NULL AND s.actualStartTS IS NULL ") 153 .append(" AND s.expectedStartTS <= :currentTimeStamp))"); 154 queryParams.put("currentTimeStamp",currentTime); 155 } 156 else if (status.equals(EventStatus.DURATION_MET)) { 157 sb.append("(s.expectedDuration <> -1 AND s.actualDuration <> -1 ").append( 158 " AND s.expectedDuration >= s.actualDuration) "); 159 } 160 161 else if (status.equals(EventStatus.DURATION_MISS)) { 162 sb.append("((s.expectedDuration <> -1 AND s.actualDuration <> -1 ") 163 .append("AND s.expectedDuration < s.actualDuration) ") 164 .append("OR s.eventStatus = 'DURATION_MISS')"); 165 } 166 else if (status.equals(EventStatus.END_MET)) { 167 sb.append("(s.expectedEndTS IS NOT NULL AND s.actualEndTS IS NOT NULL ").append( 168 " AND s.expectedEndTS <= s.actualEndTS) "); 169 } 170 else if (status.equals(EventStatus.END_MISS)) { 171 sb.append("((s.expectedEndTS IS NOT NULL AND s.actualEndTS IS NOT NULL ") 172 .append("AND s.expectedEndTS <= s.actualEndTS) ") 173 .append("OR (s.expectedEndTS IS NOT NULL AND s.actualEndTS IS NULL ") 174 .append("AND s.expectedEndTS <= :currentTimeStamp))"); 175 queryParams.put("currentTimeStamp",currentTime); 176 } 177 ind++; 178 } 179 if (eventStatuses.size() > 1) { 180 sb.append(")"); 181 } 182 } 183 184 public static class SLASummaryFilter { 185 186 private String appName; 187 private String jobId; 188 private String parentId; 189 private List<SLAEvent.EventStatus> eventStatus; 190 private Date nominalStart; 191 private Date nominalEnd; 192 193 public SLASummaryFilter() { 194 } 195 196 public String getAppName() { 197 return appName; 198 } 199 200 public void setAppName(String appName) { 201 this.appName = appName; 202 } 203 204 public String getJobId() { 205 return jobId; 206 } 207 208 public void setJobId(String jobId) { 209 this.jobId = jobId; 210 } 211 212 public String getParentId() { 213 return parentId; 214 } 215 216 public void setParentId(String parentId) { 217 this.parentId = parentId; 218 } 219 220 public Date getNominalStart() { 221 return nominalStart; 222 } 223 224 public void setNominalStart(Date nominalStart) { 225 this.nominalStart = nominalStart; 226 } 227 228 public Date getNominalEnd() { 229 return nominalEnd; 230 } 231 232 public void setNominalEnd(Date nominalEnd) { 233 this.nominalEnd = nominalEnd; 234 } 235 236 public List<SLAEvent.EventStatus> getEventStatus() { 237 return this.eventStatus; 238 } 239 240 public void setEventStatus(final String eventStatus) { 241 if (this.eventStatus == null) { 242 this.eventStatus = new ArrayList<>(); 243 } 244 245 if (eventStatus.equalsIgnoreCase(SLASummaryBean.EVENT_STATUS_ALL)) { 246 this.eventStatus.addAll(Arrays.asList(SLAEvent.EventStatus.values())); 247 } 248 else { 249 final String[] eventStatuses = eventStatus.split(SLASummaryBean.EVENT_STATUS_SEPARATOR); 250 251 for (final String es : eventStatuses) { 252 this.eventStatus.add(SLAEvent.EventStatus.valueOf(es)); 253 } 254 } 255 } 256 } 257}