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.store;
020
021import java.sql.Timestamp;
022import java.util.Date;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.oozie.ErrorCode;
027import org.apache.oozie.client.OozieClient;
028import org.apache.oozie.executor.jpa.JPAExecutorException;
029import org.apache.oozie.util.DateUtils;
030import org.apache.oozie.util.XLog;
031
032public class StoreStatusFilter {
033    public static final String coordSeletStr = "Select w.id, w.appName, w.statusStr, w.user, w.group, w.startTimestamp, " +
034            "w.endTimestamp, w.appPath, w.concurrency, w.frequency, w.lastActionTimestamp, w.nextMaterializedTimestamp, " +
035            "w.createdTimestamp, w.timeUnitStr, w.timeZone, w.timeOut, w.bundleId from CoordinatorJobBean w";
036
037    public static final String coordCountStr = "Select count(w) from CoordinatorJobBean w";
038
039    public static final String wfSeletStr = "Select w.id, w.appName, w.statusStr, w.run, w.user, w.group, w.createdTimestamp, " +
040            "w.startTimestamp, w.lastModifiedTimestamp, w.endTimestamp from WorkflowJobBean w";
041
042    public static final String wfCountStr = "Select count(w) from WorkflowJobBean w";
043
044    public static final String bundleSeletStr = "Select w.id, w.appName, w.appPath, w.conf, w.statusStr, w.kickoffTimestamp, " +
045            "w.startTimestamp, w.endTimestamp, w.pauseTimestamp, w.createdTimestamp, w.user, w.group, w.timeUnitStr, " +
046            "w.timeOut from BundleJobBean w";
047
048    public static final String bundleCountStr = "Select count(w) from BundleJobBean w";
049
050    public static final String TIME_FORMAT = " Specify time either in UTC format (yyyy-MM-dd'T'HH:mm'Z') or " +
051            "a offset value in days/hours/minutes e.g. (-2d/h/m) from the current time.";
052
053    private static final String textFilterStr = "(w.appName LIKE :text1 OR w.user LIKE :text2 OR w.id = :text3)";
054
055
056    public static void filter(Map<String, List<String>> filter, List<String> orArray, List<String> colArray,
057           List<Object> valArray, StringBuilder sb, String seletStr, String countStr) throws JPAExecutorException {
058        boolean isStatus = false;
059        boolean isAppName = false;
060        boolean isUser = false;
061        boolean isEnabled = false;
062        boolean isFrequency = false;
063        boolean isId = false;
064        boolean isUnit = false;
065
066        int index = 0;
067
068        for (Map.Entry<String, List<String>> entry : filter.entrySet()) {
069            String colName = null;
070            String colVar = null;
071            if (entry.getKey().equals(OozieClient.FILTER_GROUP)) {
072                XLog.getLog(StoreStatusFilter.class).warn("Filter by 'group' is not supported anymore");
073            }
074            else {
075                if (entry.getKey().equals(OozieClient.FILTER_STATUS)) {
076                    List<String> values = filter.get(OozieClient.FILTER_STATUS);
077                    colName = "status";
078                    for (int i = 0; i < values.size(); i++) {
079                        colVar = "status";
080                        colVar = colVar + index;
081                        if (!isEnabled && !isStatus) {
082                            sb.append(seletStr).append(" where w.statusStr IN (:status" + index);
083                            isStatus = true;
084                            isEnabled = true;
085                        }
086                        else {
087                            if (isEnabled && !isStatus) {
088                                sb.append(" and w.statusStr IN (:status" + index);
089                                isStatus = true;
090                            }
091                            else {
092                                if (isStatus) {
093                                    sb.append(", :status" + index);
094                                }
095                            }
096                        }
097                        if (i == values.size() - 1) {
098                            sb.append(")");
099                        }
100                        index++;
101                        valArray.add(values.get(i));
102                        orArray.add(colName);
103                        colArray.add(colVar);
104                    }
105                }
106                else {
107                    if (entry.getKey().equals(OozieClient.FILTER_NAME)) {
108                        List<String> values = filter.get(OozieClient.FILTER_NAME);
109                        colName = "appName";
110                        for (int i = 0; i < values.size(); i++) {
111                            colVar = "appName";
112                            colVar = colVar + index;
113                            if (!isEnabled && !isAppName) {
114                                sb.append(seletStr).append(" where w.appName IN (:appName" + index);
115                                isAppName = true;
116                                isEnabled = true;
117                            }
118                            else {
119                                if (isEnabled && !isAppName) {
120                                    sb.append(" and w.appName IN (:appName" + index);
121                                    isAppName = true;
122                                }
123                                else {
124                                    if (isAppName) {
125                                        sb.append(", :appName" + index);
126                                    }
127                                }
128                            }
129                            if (i == values.size() - 1) {
130                                sb.append(")");
131                            }
132                            index++;
133                            valArray.add(values.get(i));
134                            orArray.add(colName);
135                            colArray.add(colVar);
136                        }
137                    }
138                    else {
139                        if (entry.getKey().equals(OozieClient.FILTER_USER)) {
140                            List<String> values = filter.get(OozieClient.FILTER_USER);
141                            colName = "user";
142                            for (int i = 0; i < values.size(); i++) {
143                                colVar = "user";
144                                colVar = colVar + index;
145                                if (!isEnabled && !isUser) {
146                                    sb.append(seletStr).append(" where w.user IN (:user" + index);
147                                    isUser = true;
148                                    isEnabled = true;
149                                }
150                                else {
151                                    if (isEnabled && !isUser) {
152                                        sb.append(" and w.user IN (:user" + index);
153                                        isUser = true;
154                                    }
155                                    else {
156                                        if (isUser) {
157                                            sb.append(", :user" + index);
158                                        }
159                                    }
160                                }
161                                if (i == values.size() - 1) {
162                                    sb.append(")");
163                                }
164                                index++;
165                                valArray.add(values.get(i));
166                                orArray.add(colName);
167                                colArray.add(colVar);
168                            }
169                        }
170                        else if (entry.getKey().equals(OozieClient.FILTER_FREQUENCY)) {
171                            List<String> values = filter.get(OozieClient.FILTER_FREQUENCY);
172                            colName = "frequency";
173                            for (int i = 0; i < values.size(); i++) {
174                                colVar = "frequency";
175                                colVar = colVar + index;
176                                if (!isEnabled && !isFrequency) {
177                                    sb.append(seletStr).append(" where w.frequency IN (:frequency" + index);
178                                    isFrequency = true;
179                                    isEnabled = true;
180                                }
181                                else {
182                                    if (isEnabled && !isFrequency) {
183                                        sb.append(" and w.frequency IN (:frequency" + index);
184                                        isFrequency = true;
185                                    }
186                                    else {
187                                        if (isFrequency) {
188                                            sb.append(", :frequency" + index);
189                                        }
190                                    }
191                                }
192                                if (i == values.size() - 1) {
193                                    sb.append(")");
194                                }
195                                index++;
196                                valArray.add(values.get(i));
197                                orArray.add(colName);
198                                colArray.add(colVar);
199                            }
200                        }
201                        else if (entry.getKey().equals(OozieClient.FILTER_ID)) {
202                            List<String> values = filter.get(OozieClient.FILTER_ID);
203                            colName = "id";
204                            for (int i = 0; i < values.size(); i++) {
205                                colVar = "id";
206                                colVar = colVar + index;
207                                if (!isEnabled && !isId) {
208                                    sb.append(seletStr).append(" where w.id IN (:id" + index);
209                                    isId = true;
210                                    isEnabled = true;
211                                }
212                                else {
213                                    if (isEnabled && !isId) {
214                                        sb.append(" and w.id IN (:id" + index);
215                                        isId = true;
216                                    }
217                                    else {
218                                        if (isId) {
219                                            sb.append(", :id" + index);
220                                        }
221                                    }
222                                }
223                                if (i == values.size() - 1) {
224                                    sb.append(")");
225                                }
226                                index++;
227                                valArray.add(values.get(i));
228                                orArray.add(colName);
229                                colArray.add(colVar);
230                            }
231                        }
232                        // Filter map has time unit filter specified
233                        else if (entry.getKey().equals(OozieClient.FILTER_UNIT)) {
234                            List<String> values = filter.get(OozieClient.FILTER_UNIT);
235                            colName = "timeUnitStr";
236                            for (int i = 0; i < values.size(); ++i) {
237                                colVar = colName + index;
238                                // This unit filter value is the first condition to be added to the where clause of
239                                // query
240                                if (!isEnabled && !isUnit) {
241                                    sb.append(seletStr).append(" where w.timeUnitStr IN (:timeUnitStr" + index);
242                                    isUnit = true;
243                                    isEnabled = true;
244                                } else {
245                                    // Unit filter is neither the first nor the last condition to be added to the where
246                                    // clause of query
247                                    if (isEnabled && !isUnit) {
248                                        sb.append(" and w.timeUnitStr IN (:timeUnitStr" + index);
249                                        isUnit = true;
250                                    } else {
251                                        if (isUnit) {
252                                            sb.append(", :timeUnitStr" + index);
253                                        }
254                                    }
255                                }
256                                // This unit filter value is the last condition to be added to the where clause of query
257                                if (i == values.size() - 1) {
258                                    sb.append(")");
259                                }
260                                ++index;
261                                valArray.add(values.get(i));
262                                orArray.add(colName);
263                                colArray.add(colVar);
264                            }
265                        }
266                        else if (entry.getKey().equalsIgnoreCase(OozieClient.FILTER_CREATED_TIME_START)) {
267                            List<String> values = filter.get(OozieClient.FILTER_CREATED_TIME_START);
268                            colName = "createdTimestampStart";
269                            if (values.size() > 1) {
270                                throw new JPAExecutorException(ErrorCode.E0302,
271                                        "cannot specify multiple startcreatedtime");
272                            }
273                            colVar = colName;
274                            colVar = colVar + index;
275                            if (!isEnabled) {
276                                sb.append(seletStr).append(" where w.createdTimestamp >= :" + colVar);
277                                isEnabled = true;
278                            }
279                            else {
280                                sb.append(" and w.createdTimestamp >= :" + colVar);
281                            }
282                            index++;
283                            Date createdTime = null;
284                            try {
285                                createdTime = parseCreatedTimeString(values.get(0));
286                            }
287                            catch (Exception e) {
288                                throw new JPAExecutorException(ErrorCode.E0302, e.getMessage());
289                            }
290                            Timestamp createdTimeStamp = new Timestamp(createdTime.getTime());
291                            valArray.add(createdTimeStamp);
292                            orArray.add(colName);
293                            colArray.add(colVar);
294
295                        }
296                        else if (entry.getKey().equalsIgnoreCase(OozieClient.FILTER_CREATED_TIME_END)) {
297                            List<String> values = filter.get(OozieClient.FILTER_CREATED_TIME_END);
298                            colName = "createdTimestampEnd";
299                            if (values.size() > 1) {
300                                throw new JPAExecutorException(ErrorCode.E0302,
301                                        "cannot specify multiple endcreatedtime");
302                            }
303                            colVar = colName;
304                            colVar = colVar + index;
305                            if (!isEnabled) {
306                                sb.append(seletStr).append(" where w.createdTimestamp <= :" + colVar);
307                                isEnabled = true;
308                            }
309                            else {
310                                sb.append(" and w.createdTimestamp <= :" + colVar);
311                            }
312                            index++;
313                            Date createdTime = null;
314                            try {
315                                createdTime = parseCreatedTimeString(values.get(0));
316                            }
317                            catch (Exception e) {
318                                throw new JPAExecutorException(ErrorCode.E0302, e.getMessage());
319                            }
320                            Timestamp createdTimeStamp = new Timestamp(createdTime.getTime());
321                            valArray.add(createdTimeStamp);
322                            orArray.add(colName);
323                            colArray.add(colVar);
324                        }
325                        // job.id = text || job.appName.contains(text) || job.user.contains(text)
326                        else if (entry.getKey().equalsIgnoreCase(OozieClient.FILTER_TEXT)) {
327                            filterJobsUsingText(filter, sb, isEnabled, seletStr, valArray, orArray, colArray);
328                            isEnabled = true;
329                        }
330                    }
331                }
332            }
333        }
334    }
335
336    private static Date parseCreatedTimeString(String time) throws Exception{
337        Date createdTime = null;
338        int offset = 0;
339        if (Character.isLetter(time.charAt(time.length() - 1))) {
340            switch (time.charAt(time.length() - 1)) {
341                case 'd':
342                    offset = Integer.parseInt(time.substring(0, time.length() - 1));
343                    if(offset > 0) {
344                        throw new IllegalArgumentException("offset must be minus from currentTime.");
345                    }
346                    createdTime = org.apache.commons.lang.time.DateUtils.addDays(new Date(), offset);
347                    break;
348                case 'h':
349                    offset =  Integer.parseInt(time.substring(0, time.length() - 1));
350                    if(offset > 0) {
351                        throw new IllegalArgumentException("offset must be minus from currentTime.");
352                    }
353                    createdTime = org.apache.commons.lang.time.DateUtils.addHours(new Date(), offset);
354                    break;
355                case 'm':
356                    offset =  Integer.parseInt(time.substring(0, time.length() - 1));
357                    if(offset > 0) {
358                        throw new IllegalArgumentException("offset must be minus from currentTime.");
359                    }
360                    createdTime = org.apache.commons.lang.time.DateUtils.addMinutes(new Date(), offset);
361                    break;
362                case 'Z':
363                    createdTime = DateUtils.parseDateUTC(time);
364                    break;
365                default:
366                    throw new IllegalArgumentException("Unsupported time format: " + time + TIME_FORMAT);
367            }
368        } else {
369            throw new IllegalArgumentException("The format of time is wrong: " + time + TIME_FORMAT);
370        }
371        return createdTime;
372    }
373
374    public static String getSortBy(Map<String, List<String>> filter, String sortByStr) throws JPAExecutorException {
375        if (filter.containsKey(OozieClient.FILTER_SORT_BY)) {
376            List<String> values = filter.get(OozieClient.FILTER_SORT_BY);
377            if (values.size() > 1) {
378                throw new JPAExecutorException(ErrorCode.E0302,
379                        "cannot specify multiple sortby parameter");
380            }
381            String value = values.get(0);
382            for (OozieClient.SORT_BY sortBy : OozieClient.SORT_BY.values()) {
383                if (sortBy.toString().equalsIgnoreCase(value)) {
384                    value = sortBy.getFullname();
385                    sortByStr = " order by w.".concat(value).concat(" desc ");
386                    break;
387                }
388            }
389        }
390        return sortByStr;
391    }
392
393    public static void filterJobsUsingText(Map<String, List<String>> filter, StringBuilder sb, boolean isEnabled,
394           String seletStr, List<Object> valArray, List<String> orArray, List<String> colArray) throws JPAExecutorException {
395        List<String> values = filter.get(OozieClient.FILTER_TEXT);
396        if (values.size() != 1) {
397            throw new JPAExecutorException(ErrorCode.E0302,
398                    "cannot specify multiple strings to search");
399        }
400        if (!isEnabled) {
401            sb.append(seletStr).append(" where " + textFilterStr);
402        }
403        else {
404            sb.append(" and " + textFilterStr);
405        }
406
407        valArray.add("%" + values.get(0) + "%");
408        orArray.add("appName");
409        colArray.add("text1");
410
411        valArray.add("%" + values.get(0) + "%");
412        orArray.add("user");
413        colArray.add("text2");
414
415        valArray.add(values.get(0));
416        orArray.add("id");
417        colArray.add("text3");
418    }
419}