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.sla; 020 021import java.sql.Timestamp; 022import java.util.Date; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import javax.persistence.Basic; 028import javax.persistence.Column; 029import javax.persistence.Entity; 030import javax.persistence.Id; 031import javax.persistence.NamedQueries; 032import javax.persistence.NamedQuery; 033import javax.persistence.Table; 034 035import org.apache.oozie.AppType; 036import org.apache.oozie.client.OozieClient; 037import org.apache.oozie.client.event.SLAEvent; 038import org.apache.oozie.client.event.SLAEvent.EventStatus; 039import org.apache.oozie.client.rest.JsonBean; 040import org.apache.oozie.client.rest.JsonTags; 041import org.apache.oozie.client.rest.JsonUtils; 042import org.apache.oozie.util.DateUtils; 043import org.apache.openjpa.persistence.jdbc.Index; 044import org.json.simple.JSONArray; 045import org.json.simple.JSONObject; 046 047@Entity 048@Table(name = "SLA_SUMMARY") 049@NamedQueries({ 050 051 @NamedQuery(name = "UPDATE_SLA_SUMMARY_FOR_SLA_STATUS", query = "update SLASummaryBean w set w.slaStatus = :slaStatus, w.eventStatus = :eventStatus, w.eventProcessed = :eventProcessed, w.lastModifiedTS = :lastModifiedTS where w.jobId = :jobId"), 052 053 @NamedQuery(name = "UPDATE_SLA_SUMMARY_FOR_STATUS_ACTUAL_TIMES", query = "update SLASummaryBean w set w.slaStatus = :slaStatus, w.eventStatus = :eventStatus, w.eventProcessed = :eventProcessed, w.jobStatus = :jobStatus, w.lastModifiedTS = :lastModifiedTS, w.actualStartTS = :actualStartTS, w.actualEndTS = :actualEndTS, w.actualDuration = :actualDuration where w.jobId = :jobId"), 054 055 @NamedQuery(name = "UPDATE_SLA_SUMMARY_FOR_EXPECTED_TIMES", query = "update SLASummaryBean w set w.nominalTimeTS = :nominalTime, w.expectedStartTS = :expectedStartTime, w.expectedEndTS = :expectedEndTime, w.expectedDuration = :expectedDuration , w.lastModifiedTS = :lastModTime where w.jobId = :jobId"), 056 057 @NamedQuery(name = "UPDATE_SLA_SUMMARY_EVENTPROCESSED", query = "update SLASummaryBean w set w.eventProcessed = :eventProcessed where w.jobId = :jobId"), 058 059 @NamedQuery(name = "UPDATE_SLA_SUMMARY_LAST_MODIFIED_TIME", query = "update SLASummaryBean w set w.lastModifiedTS = :lastModifiedTS where w.jobId = :jobId"), 060 061 @NamedQuery(name = "UPDATE_SLA_SUMMARY_ALL", query = "update SLASummaryBean w set w.jobId = :jobId, w.appName = :appName, w.appType = :appType, w.nominalTimeTS = :nominalTime, w.expectedStartTS = :expectedStartTime, w.expectedEndTS = :expectedEndTime, w.expectedDuration = :expectedDuration, w.jobStatus = :jobStatus, w.slaStatus = :slaStatus, w.eventStatus = :eventStatus, w.lastModifiedTS = :lastModTime, w.user = :user, w.parentId = :parentId, w.eventProcessed = :eventProcessed, w.actualDuration = :actualDuration, w.actualEndTS = :actualEndTS, w.actualStartTS = :actualStartTS where w.jobId = :jobId"), 062 063 @NamedQuery(name = "GET_SLA_SUMMARY", query = "select OBJECT(w) from SLASummaryBean w where w.jobId = :id"), 064 065 @NamedQuery(name = "GET_SLA_SUMMARY_RECORDS_RESTART", query = "select OBJECT(w) from SLASummaryBean w where w.eventProcessed <= 7 AND w.lastModifiedTS >= :lastModifiedTime"), 066 067 @NamedQuery(name = "GET_SLA_SUMMARY_EVENTPROCESSED", query = "select w.eventProcessed from SLASummaryBean w where w.jobId = :id"), 068 069 @NamedQuery(name = "GET_SLA_SUMMARY_EVENTPROCESSED_LAST_MODIFIED", query = "select w.eventProcessed, w.lastModifiedTS from SLASummaryBean w where w.jobId = :id") 070 071}) 072 073/** 074 * Class to store all the SLA related details (summary) per job 075 */ 076public class SLASummaryBean implements JsonBean { 077 078 @Id 079 @Basic 080 @Column(name = "job_id") 081 private String jobId; 082 083 @Basic 084 @Index 085 @Column(name = "parent_id") 086 private String parentId; 087 088 @Basic 089 @Index 090 @Column(name = "app_name") 091 private String appName; 092 093 @Basic 094 @Column(name = "app_type") 095 private String appType; 096 097 @Basic 098 @Column(name = "user_name") 099 private String user; 100 101 @Basic 102 @Column(name = "created_time") 103 private Timestamp createdTimeTS = null; 104 105 @Basic 106 @Index 107 @Column(name = "nominal_time") 108 private Timestamp nominalTimeTS = null; 109 110 @Basic 111 @Column(name = "expected_start") 112 private Timestamp expectedStartTS = null; 113 114 @Basic 115 @Column(name = "expected_end") 116 private Timestamp expectedEndTS = null; 117 118 @Basic 119 @Column(name = "expected_duration") 120 private long expectedDuration = -1; 121 122 @Basic 123 @Column(name = "actual_start") 124 private Timestamp actualStartTS = null; 125 126 @Basic 127 @Column(name = "actual_end") 128 private Timestamp actualEndTS = null; 129 130 @Basic 131 @Column(name = "actual_duration") 132 private long actualDuration = -1; 133 134 @Basic 135 @Column(name = "job_status") 136 private String jobStatus; 137 138 @Basic 139 @Column(name = "event_status") 140 private String eventStatus; 141 142 @Basic 143 @Column(name = "sla_status") 144 private String slaStatus; 145 146 @Basic 147 @Index 148 @Column(name = "event_processed") 149 private byte eventProcessed = 0; 150 151 @Basic 152 @Index 153 @Column(name = "last_modified") 154 private Timestamp lastModifiedTS = null; 155 156 public SLASummaryBean() { 157 } 158 159 public SLASummaryBean(SLACalcStatus slaCalc) { 160 SLARegistrationBean reg = slaCalc.getSLARegistrationBean(); 161 setId(slaCalc.getId()); 162 setAppName(reg.getAppName()); 163 setAppType(reg.getAppType()); 164 setNominalTime(reg.getNominalTime()); 165 setExpectedStart(reg.getExpectedStart()); 166 setExpectedEnd(reg.getExpectedEnd()); 167 setExpectedDuration(reg.getExpectedDuration()); 168 setJobStatus(slaCalc.getJobStatus()); 169 setSLAStatus(slaCalc.getSLAStatus()); 170 setEventStatus(slaCalc.getEventStatus()); 171 setLastModifiedTime(slaCalc.getLastModifiedTime()); 172 setUser(reg.getUser()); 173 setParentId(reg.getParentId()); 174 setEventProcessed(slaCalc.getEventProcessed()); 175 setActualDuration(slaCalc.getActualDuration()); 176 setActualEnd(slaCalc.getActualEnd()); 177 setActualStart(slaCalc.getActualStart()); 178 } 179 180 public String getId() { 181 return jobId; 182 } 183 184 public void setId(String jobId) { 185 this.jobId = jobId; 186 } 187 188 public String getParentId() { 189 return parentId; 190 } 191 192 public void setParentId(String parentId) { 193 this.parentId = parentId; 194 } 195 196 public Timestamp getCreatedTimestamp() { 197 return createdTimeTS; 198 } 199 200 public void setCreatedTimestamp(Timestamp createdTime) { 201 this.createdTimeTS = createdTime; 202 } 203 204 public Date getCreatedTime() { 205 return DateUtils.toDate(createdTimeTS); 206 } 207 208 public void setCreatedTime(Date createdTime) { 209 this.createdTimeTS = DateUtils.convertDateToTimestamp(createdTime); 210 } 211 212 public Date getNominalTime() { 213 return DateUtils.toDate(nominalTimeTS); 214 } 215 216 public Timestamp getNominalTimestamp() { 217 return this.nominalTimeTS; 218 } 219 220 public void setNominalTime(Date nominalTime) { 221 this.nominalTimeTS = DateUtils.convertDateToTimestamp(nominalTime); 222 } 223 224 225 public Date getExpectedStart() { 226 return DateUtils.toDate(expectedStartTS); 227 } 228 229 public Timestamp getExpectedStartTimestamp() { 230 return this.expectedStartTS; 231 } 232 233 public void setExpectedStart(Date expectedStart) { 234 this.expectedStartTS = DateUtils.convertDateToTimestamp(expectedStart); 235 } 236 237 public Date getExpectedEnd() { 238 return DateUtils.toDate(expectedEndTS); 239 } 240 241 public Timestamp getExpectedEndTimestamp() { 242 return this.expectedEndTS; 243 } 244 public void setExpectedEnd(Date expectedEnd) { 245 this.expectedEndTS = DateUtils.convertDateToTimestamp(expectedEnd); 246 } 247 248 public long getExpectedDuration() { 249 return expectedDuration; 250 } 251 252 public void setExpectedDuration(long expectedDuration) { 253 this.expectedDuration = expectedDuration; 254 } 255 256 public Date getActualStart() { 257 return DateUtils.toDate(actualStartTS); 258 } 259 260 public Timestamp getActualStartTimestamp() { 261 return this.actualStartTS; 262 } 263 264 public void setActualStart(Date actualStart) { 265 this.actualStartTS = DateUtils.convertDateToTimestamp(actualStart); 266 } 267 268 public Date getActualEnd() { 269 return DateUtils.toDate(actualEndTS); 270 } 271 272 public Timestamp getActualEndTimestamp() { 273 return this.actualEndTS; 274 } 275 276 public void setActualEnd(Date actualEnd) { 277 this.actualEndTS = DateUtils.convertDateToTimestamp(actualEnd); 278 } 279 280 public long getActualDuration() { 281 return actualDuration; 282 } 283 284 public void setActualDuration(long actualDuration) { 285 this.actualDuration = actualDuration; 286 } 287 288 public String getJobStatus() { 289 return jobStatus; 290 } 291 292 public void setJobStatus(String status) { 293 this.jobStatus = status; 294 } 295 296 public SLAEvent.EventStatus getEventStatus() { 297 return (eventStatus != null ? SLAEvent.EventStatus.valueOf(eventStatus) : null); 298 } 299 300 public void setEventStatus(SLAEvent.EventStatus eventStatus) { 301 this.eventStatus = (eventStatus != null ? eventStatus.name() : null); 302 } 303 304 public SLAEvent.SLAStatus getSLAStatus() { 305 return (slaStatus != null ? SLAEvent.SLAStatus.valueOf(slaStatus) : null); 306 } 307 308 public String getSLAStatusString() { 309 return slaStatus; 310 } 311 312 public String getEventStatusString() { 313 return eventStatus; 314 } 315 316 public void setSLAStatus(SLAEvent.SLAStatus stage) { 317 this.slaStatus = (stage != null ? stage.name() : null); 318 } 319 320 public String getUser() { 321 return user; 322 } 323 324 public void setUser(String user) { 325 this.user = user; 326 } 327 328 public String getAppName() { 329 return appName; 330 } 331 332 public void setAppName(String appName) { 333 this.appName = appName; 334 } 335 336 public AppType getAppType() { 337 return AppType.valueOf(appType); 338 } 339 340 public void setAppType(AppType appType) { 341 this.appType = appType.toString(); 342 } 343 344 public byte getEventProcessed() { 345 return eventProcessed; 346 } 347 348 public void setEventProcessed(int eventProcessed) { 349 this.eventProcessed = (byte)eventProcessed; 350 } 351 352 public Date getLastModifiedTime() { 353 return DateUtils.toDate(lastModifiedTS); 354 } 355 356 public Timestamp getLastModifiedTimestamp() { 357 return this.lastModifiedTS; 358 } 359 360 public void setLastModifiedTime(Date lastModified) { 361 this.lastModifiedTS = DateUtils.convertDateToTimestamp(lastModified); 362 } 363 364 @Override 365 public JSONObject toJSONObject() { 366 return toJSONObject(null); 367 } 368 369 @Override 370 @SuppressWarnings("unchecked") 371 public JSONObject toJSONObject(String timeZoneId) { 372 JSONObject json = new JSONObject(); 373 Map<EventStatus,Long> eventMap = calculateEventStatus(); 374 StringBuilder eventStatusStr = new StringBuilder(); 375 boolean first = true; 376 for(EventStatus e: eventMap.keySet()) { 377 if(!first) { 378 eventStatusStr.append(","); 379 } 380 eventStatusStr.append(e.toString()); 381 first = false; 382 } 383 json.put(JsonTags.SLA_SUMMARY_ID, jobId); 384 if (parentId != null) { 385 json.put(JsonTags.SLA_SUMMARY_PARENT_ID, parentId); 386 } 387 json.put(JsonTags.SLA_SUMMARY_APP_NAME, appName); 388 json.put(JsonTags.SLA_SUMMARY_APP_TYPE, appType); 389 json.put(JsonTags.SLA_SUMMARY_USER, user); 390 json.put(JsonTags.SLA_SUMMARY_NOMINAL_TIME, getTimeOnTimeZone(nominalTimeTS, timeZoneId)); 391 if (expectedStartTS != null) { 392 json.put(JsonTags.SLA_SUMMARY_EXPECTED_START, getTimeOnTimeZone(expectedStartTS, timeZoneId)); 393 } else { 394 json.put(JsonTags.SLA_SUMMARY_EXPECTED_START, null); 395 } 396 397 if (actualStartTS != null) { 398 json.put(JsonTags.SLA_SUMMARY_ACTUAL_START, getTimeOnTimeZone(actualStartTS, timeZoneId)); 399 } 400 else { 401 json.put(JsonTags.SLA_SUMMARY_ACTUAL_START, null); 402 } 403 Long startDelay = eventMap.get(EventStatus.START_MET) != null ? eventMap.get(EventStatus.START_MET) : eventMap 404 .get(EventStatus.START_MISS); 405 if (startDelay != null) { 406 json.put(JsonTags.SLA_SUMMARY_START_DELAY, startDelay); 407 } 408 if (expectedEndTS != null ) { 409 json.put(JsonTags.SLA_SUMMARY_EXPECTED_END, getTimeOnTimeZone(expectedEndTS,timeZoneId)); 410 } else { 411 json.put(JsonTags.SLA_SUMMARY_ACTUAL_END, null); 412 } 413 if (actualEndTS != null) { 414 json.put(JsonTags.SLA_SUMMARY_ACTUAL_END, getTimeOnTimeZone(actualEndTS,timeZoneId)); 415 } 416 else { 417 json.put(JsonTags.SLA_SUMMARY_ACTUAL_END, null); 418 } 419 Long endDelay = eventMap.get(EventStatus.END_MET) != null ? eventMap.get(EventStatus.END_MET) : eventMap 420 .get(EventStatus.END_MISS); 421 if (endDelay != null) { 422 json.put(JsonTags.SLA_SUMMARY_END_DELAY, endDelay); 423 } 424 json.put(JsonTags.SLA_SUMMARY_EXPECTED_DURATION, expectedDuration); 425 if (actualDuration == -1 && expectedDuration != -1 && actualStartTS != null) { 426 long currentDur = new Date().getTime() - actualStartTS.getTime(); 427 json.put(JsonTags.SLA_SUMMARY_ACTUAL_DURATION, currentDur); 428 } 429 else { 430 json.put(JsonTags.SLA_SUMMARY_ACTUAL_DURATION, actualDuration); 431 } 432 Long durationDelay = eventMap.get(EventStatus.DURATION_MET) != null ? eventMap.get(EventStatus.DURATION_MET) 433 : eventMap.get(EventStatus.DURATION_MISS); 434 if (durationDelay != null) { 435 json.put(JsonTags.SLA_SUMMARY_DURATION_DELAY, durationDelay / (1000 * 60)); 436 } 437 json.put(JsonTags.SLA_SUMMARY_JOB_STATUS, jobStatus); 438 json.put(JsonTags.SLA_SUMMARY_SLA_STATUS, slaStatus); 439 json.put(JsonTags.SLA_SUMMARY_EVENT_STATUS, eventStatusStr.toString()); 440 json.put(JsonTags.SLA_SUMMARY_LAST_MODIFIED, getTimeOnTimeZone(lastModifiedTS, timeZoneId)); 441 return json; 442 } 443 444 private Object getTimeOnTimeZone(Timestamp ts, String timeZoneId) { 445 Object ret = null; 446 if(timeZoneId == null) { 447 ret = new Long(String.valueOf(ts.getTime())); 448 } else { 449 ret = JsonUtils.formatDateRfc822(ts, timeZoneId); 450 } 451 return ret; 452 } 453 454 private Map<EventStatus, Long> calculateEventStatus() { 455 Map<EventStatus, Long> events = new HashMap<EventStatus, Long>(); 456 if (expectedStartTS != null) { 457 if (actualStartTS != null) { 458 long diff = (actualStartTS.getTime() - expectedStartTS.getTime()) / (1000 * 60); 459 if (diff > 0) { 460 events.put(EventStatus.START_MISS, diff); 461 } 462 else { 463 events.put(EventStatus.START_MET, diff); 464 } 465 } 466 else { 467 long diff = (new Date().getTime() - expectedStartTS.getTime()) / (1000 * 60); 468 if (diff > 0) { 469 events.put(EventStatus.START_MISS, diff); 470 } 471 } 472 } 473 if (expectedDuration != -1) { 474 if (actualDuration != -1) { 475 long diff = actualDuration - expectedDuration; 476 if (diff > 0) { 477 events.put(EventStatus.DURATION_MISS, diff); 478 } 479 else { 480 events.put(EventStatus.DURATION_MET, diff); 481 } 482 } 483 else { 484 if (actualStartTS != null) { 485 long currentDur = new Date().getTime() - actualStartTS.getTime(); 486 if (expectedDuration < currentDur) { 487 events.put(EventStatus.DURATION_MISS, currentDur - expectedDuration); 488 } 489 } 490 } 491 } 492 if (expectedEndTS != null) { 493 if (actualEndTS != null) { 494 long diff = (actualEndTS.getTime() - expectedEndTS.getTime()) / (1000 * 60); 495 if (diff > 0) { 496 events.put(EventStatus.END_MISS, diff); 497 } 498 else { 499 events.put(EventStatus.END_MET, diff); 500 } 501 } 502 else { 503 long diff = (new Date().getTime() - expectedEndTS.getTime()) / (1000 * 60); 504 if (diff > 0) { 505 events.put(EventStatus.END_MISS, diff); 506 } 507 } 508 } 509 return events; 510 } 511 /** 512 * Convert a sla summary list into a json object. 513 * 514 * @param slaSummaryList sla summary list. 515 * @param timeZoneId time zone to use for dates in the JSON array. 516 * @return the corresponding JSON object. 517 */ 518 @SuppressWarnings("unchecked") 519 public static JSONObject toJSONObject(List<? extends SLASummaryBean> slaSummaryList, String timeZoneId) { 520 JSONObject json = new JSONObject(); 521 JSONArray array = new JSONArray(); 522 if (slaSummaryList != null) { 523 for (SLASummaryBean summary : slaSummaryList) { 524 array.add(summary.toJSONObject(timeZoneId)); 525 } 526 } 527 json.put(JsonTags.SLA_SUMMARY_LIST, array); 528 return json; 529 } 530 531 @SuppressWarnings("unchecked") 532 public static JSONObject toJSONObject(List<? extends SLASummaryBean> slaSummaryList, 533 Map<String, Map<String, String>> slaConfigMap, String timeZoneId) { 534 JSONObject json = new JSONObject(); 535 JSONArray array = new JSONArray(); 536 if (slaSummaryList != null) { 537 for (SLASummaryBean summary : slaSummaryList) { 538 JSONObject slaJson = summary.toJSONObject(timeZoneId); 539 String slaAlertStatus = ""; 540 if (slaConfigMap.containsKey(summary.getId())) { 541 slaAlertStatus = slaConfigMap.get(summary.getId()).containsKey(OozieClient.SLA_DISABLE_ALERT) ? "Disabled" 542 : "Enabled"; 543 } 544 slaJson.put(JsonTags.SLA_ALERT_STATUS, slaAlertStatus); 545 array.add(slaJson); 546 } 547 } 548 json.put(JsonTags.SLA_SUMMARY_LIST, array); 549 return json; 550 } 551}