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}