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}