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
054    public static void filter(Map<String, List<String>> filter, List<String> orArray, List<String> colArray,
055           List<Object> valArray, StringBuilder sb, String seletStr, String countStr) throws JPAExecutorException {
056        boolean isStatus = false;
057        boolean isAppName = false;
058        boolean isUser = false;
059        boolean isEnabled = false;
060        boolean isFrequency = false;
061        boolean isId = false;
062        boolean isUnit = false;
063
064        int index = 0;
065
066        for (Map.Entry<String, List<String>> entry : filter.entrySet()) {
067            String colName = null;
068            String colVar = null;
069            if (entry.getKey().equals(OozieClient.FILTER_GROUP)) {
070                XLog.getLog(StoreStatusFilter.class).warn("Filter by 'group' is not supported anymore");
071            }
072            else {
073                if (entry.getKey().equals(OozieClient.FILTER_STATUS)) {
074                    List<String> values = filter.get(OozieClient.FILTER_STATUS);
075                    colName = "status";
076                    for (int i = 0; i < values.size(); i++) {
077                        colVar = "status";
078                        colVar = colVar + index;
079                        if (!isEnabled && !isStatus) {
080                            sb.append(seletStr).append(" where w.statusStr IN (:status" + index);
081                            isStatus = true;
082                            isEnabled = true;
083                        }
084                        else {
085                            if (isEnabled && !isStatus) {
086                                sb.append(" and w.statusStr IN (:status" + index);
087                                isStatus = true;
088                            }
089                            else {
090                                if (isStatus) {
091                                    sb.append(", :status" + index);
092                                }
093                            }
094                        }
095                        if (i == values.size() - 1) {
096                            sb.append(")");
097                        }
098                        index++;
099                        valArray.add(values.get(i));
100                        orArray.add(colName);
101                        colArray.add(colVar);
102                    }
103                }
104                else {
105                    if (entry.getKey().equals(OozieClient.FILTER_NAME)) {
106                        List<String> values = filter.get(OozieClient.FILTER_NAME);
107                        colName = "appName";
108                        for (int i = 0; i < values.size(); i++) {
109                            colVar = "appName";
110                            colVar = colVar + index;
111                            if (!isEnabled && !isAppName) {
112                                sb.append(seletStr).append(" where w.appName IN (:appName" + index);
113                                isAppName = true;
114                                isEnabled = true;
115                            }
116                            else {
117                                if (isEnabled && !isAppName) {
118                                    sb.append(" and w.appName IN (:appName" + index);
119                                    isAppName = true;
120                                }
121                                else {
122                                    if (isAppName) {
123                                        sb.append(", :appName" + index);
124                                    }
125                                }
126                            }
127                            if (i == values.size() - 1) {
128                                sb.append(")");
129                            }
130                            index++;
131                            valArray.add(values.get(i));
132                            orArray.add(colName);
133                            colArray.add(colVar);
134                        }
135                    }
136                    else {
137                        if (entry.getKey().equals(OozieClient.FILTER_USER)) {
138                            List<String> values = filter.get(OozieClient.FILTER_USER);
139                            colName = "user";
140                            for (int i = 0; i < values.size(); i++) {
141                                colVar = "user";
142                                colVar = colVar + index;
143                                if (!isEnabled && !isUser) {
144                                    sb.append(seletStr).append(" where w.user IN (:user" + index);
145                                    isUser = true;
146                                    isEnabled = true;
147                                }
148                                else {
149                                    if (isEnabled && !isUser) {
150                                        sb.append(" and w.user IN (:user" + index);
151                                        isUser = true;
152                                    }
153                                    else {
154                                        if (isUser) {
155                                            sb.append(", :user" + index);
156                                        }
157                                    }
158                                }
159                                if (i == values.size() - 1) {
160                                    sb.append(")");
161                                }
162                                index++;
163                                valArray.add(values.get(i));
164                                orArray.add(colName);
165                                colArray.add(colVar);
166                            }
167                        }
168                        else if (entry.getKey().equals(OozieClient.FILTER_FREQUENCY)) {
169                            List<String> values = filter.get(OozieClient.FILTER_FREQUENCY);
170                            colName = "frequency";
171                            for (int i = 0; i < values.size(); i++) {
172                                colVar = "frequency";
173                                colVar = colVar + index;
174                                if (!isEnabled && !isFrequency) {
175                                    sb.append(seletStr).append(" where w.frequency IN (:frequency" + index);
176                                    isFrequency = true;
177                                    isEnabled = true;
178                                }
179                                else {
180                                    if (isEnabled && !isFrequency) {
181                                        sb.append(" and w.frequency IN (:frequency" + index);
182                                        isFrequency = true;
183                                    }
184                                    else {
185                                        if (isFrequency) {
186                                            sb.append(", :frequency" + index);
187                                        }
188                                    }
189                                }
190                                if (i == values.size() - 1) {
191                                    sb.append(")");
192                                }
193                                index++;
194                                valArray.add(values.get(i));
195                                orArray.add(colName);
196                                colArray.add(colVar);
197                            }
198                        }
199                        else if (entry.getKey().equals(OozieClient.FILTER_ID)) {
200                            List<String> values = filter.get(OozieClient.FILTER_ID);
201                            colName = "id";
202                            for (int i = 0; i < values.size(); i++) {
203                                colVar = "id";
204                                colVar = colVar + index;
205                                if (!isEnabled && !isId) {
206                                    sb.append(seletStr).append(" where w.id IN (:id" + index);
207                                    isId = true;
208                                    isEnabled = true;
209                                }
210                                else {
211                                    if (isEnabled && !isId) {
212                                        sb.append(" and w.id IN (:id" + index);
213                                        isId = true;
214                                    }
215                                    else {
216                                        if (isId) {
217                                            sb.append(", :id" + index);
218                                        }
219                                    }
220                                }
221                                if (i == values.size() - 1) {
222                                    sb.append(")");
223                                }
224                                index++;
225                                valArray.add(values.get(i));
226                                orArray.add(colName);
227                                colArray.add(colVar);
228                            }
229                        }
230                        // Filter map has time unit filter specified
231                        else if (entry.getKey().equals(OozieClient.FILTER_UNIT)) {
232                            List<String> values = filter.get(OozieClient.FILTER_UNIT);
233                            colName = "timeUnitStr";
234                            for (int i = 0; i < values.size(); ++i) {
235                                colVar = colName + index;
236                                // This unit filter value is the first condition to be added to the where clause of
237                                // query
238                                if (!isEnabled && !isUnit) {
239                                    sb.append(seletStr).append(" where w.timeUnitStr IN (:timeUnitStr" + index);
240                                    isUnit = true;
241                                    isEnabled = true;
242                                } else {
243                                    // Unit filter is neither the first nor the last condition to be added to the where
244                                    // clause of query
245                                    if (isEnabled && !isUnit) {
246                                        sb.append(" and w.timeUnitStr IN (:timeUnitStr" + index);
247                                        isUnit = true;
248                                    } else {
249                                        if (isUnit) {
250                                            sb.append(", :timeUnitStr" + index);
251                                        }
252                                    }
253                                }
254                                // This unit filter value is the last condition to be added to the where clause of query
255                                if (i == values.size() - 1) {
256                                    sb.append(")");
257                                }
258                                ++index;
259                                valArray.add(values.get(i));
260                                orArray.add(colName);
261                                colArray.add(colVar);
262                            }
263                        }
264                        else if (entry.getKey().equalsIgnoreCase(OozieClient.FILTER_CREATED_TIME_START)) {
265                            List<String> values = filter.get(OozieClient.FILTER_CREATED_TIME_START);
266                            colName = "createdTimestampStart";
267                            if (values.size() > 1) {
268                                throw new JPAExecutorException(ErrorCode.E0302,
269                                        "cannot specify multiple startcreatedtime");
270                            }
271                            colVar = colName;
272                            colVar = colVar + index;
273                            if (!isEnabled) {
274                                sb.append(seletStr).append(" where w.createdTimestamp >= :" + colVar);
275                                isEnabled = true;
276                            }
277                            else {
278                                sb.append(" and w.createdTimestamp >= :" + colVar);
279                            }
280                            index++;
281                            Date createdTime = null;
282                            try {
283                                createdTime = parseCreatedTimeString(values.get(0));
284                            }
285                            catch (Exception e) {
286                                throw new JPAExecutorException(ErrorCode.E0302, e.getMessage());
287                            }
288                            Timestamp createdTimeStamp = new Timestamp(createdTime.getTime());
289                            valArray.add(createdTimeStamp);
290                            orArray.add(colName);
291                            colArray.add(colVar);
292
293                        }
294                        else if (entry.getKey().equalsIgnoreCase(OozieClient.FILTER_CREATED_TIME_END)) {
295                            List<String> values = filter.get(OozieClient.FILTER_CREATED_TIME_END);
296                            colName = "createdTimestampEnd";
297                            if (values.size() > 1) {
298                                throw new JPAExecutorException(ErrorCode.E0302,
299                                        "cannot specify multiple endcreatedtime");
300                            }
301                            colVar = colName;
302                            colVar = colVar + index;
303                            if (!isEnabled) {
304                                sb.append(seletStr).append(" where w.createdTimestamp <= :" + colVar);
305                                isEnabled = true;
306                            }
307                            else {
308                                sb.append(" and w.createdTimestamp <= :" + colVar);
309                            }
310                            index++;
311                            Date createdTime = null;
312                            try {
313                                createdTime = parseCreatedTimeString(values.get(0));
314                            }
315                            catch (Exception e) {
316                                throw new JPAExecutorException(ErrorCode.E0302, e.getMessage());
317                            }
318                            Timestamp createdTimeStamp = new Timestamp(createdTime.getTime());
319                            valArray.add(createdTimeStamp);
320                            orArray.add(colName);
321                            colArray.add(colVar);
322                        }
323                    }
324                }
325            }
326        }
327    }
328
329    private static Date parseCreatedTimeString(String time) throws Exception{
330        Date createdTime = null;
331        int offset = 0;
332        if (Character.isLetter(time.charAt(time.length() - 1))) {
333            switch (time.charAt(time.length() - 1)) {
334                case 'd':
335                    offset = Integer.parseInt(time.substring(0, time.length() - 1));
336                    if(offset > 0) {
337                        throw new IllegalArgumentException("offset must be minus from currentTime.");
338                    }
339                    createdTime = org.apache.commons.lang.time.DateUtils.addDays(new Date(), offset);
340                    break;
341                case 'h':
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.addHours(new Date(), offset);
347                    break;
348                case 'm':
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.addMinutes(new Date(), offset);
354                    break;
355                case 'Z':
356                    createdTime = DateUtils.parseDateUTC(time);
357                    break;
358                default:
359                    throw new IllegalArgumentException("Unsupported time format: " + time + TIME_FORMAT);
360            }
361        } else {
362            throw new IllegalArgumentException("The format of time is wrong: " + time + TIME_FORMAT);
363        }
364        return createdTime;
365    }
366
367    public static String getSortBy(Map<String, List<String>> filter, String sortByStr) throws JPAExecutorException {
368        if (filter.containsKey(OozieClient.FILTER_SORT_BY)) {
369            List<String> values = filter.get(OozieClient.FILTER_SORT_BY);
370            if (values.size() > 1) {
371                throw new JPAExecutorException(ErrorCode.E0302,
372                        "cannot specify multiple sortby parameter");
373            }
374            String value = values.get(0);
375            for (OozieClient.SORT_BY sortBy : OozieClient.SORT_BY.values()) {
376                if (sortBy.toString().equalsIgnoreCase(value)) {
377                    value = sortBy.getFullname();
378                    sortByStr = " order by w.".concat(value).concat(" desc ");
379                    break;
380                }
381            }
382        }
383        return sortByStr;
384    }
385}