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 */ 018package org.apache.oozie.util; 019 020import java.util.Date; 021import java.util.List; 022import java.util.TimeZone; 023 024import org.apache.commons.lang.StringUtils; 025import org.quartz.CronExpression; 026import java.text.ParseException; 027 028/** 029 * Utility class to check common parameter preconditions. 030 */ 031public class ParamChecker { 032 033 /** 034 * Check that a value is not null. If null throws an IllegalArgumentException. 035 * 036 * @param obj value. 037 * @param name parameter name for the exception message. 038 * @return the given value. 039 */ 040 public static <T> T notNull(T obj, String name) { 041 if (obj == null) { 042 throw new IllegalArgumentException(name + " cannot be null"); 043 } 044 return obj; 045 } 046 047 /** 048 * Check that a list is not null and that none of its elements is null. If null or if the list has emtpy elements 049 * throws an IllegalArgumentException. 050 * 051 * @param list the list of strings. 052 * @param name parameter name for the exception message. 053 * @return the given list. 054 */ 055 public static <T> List<T> notNullElements(List<T> list, String name) { 056 notNull(list, name); 057 for (int i = 0; i < list.size(); i++) { 058 notNull(list.get(i), XLog.format("list [{0}] element [{1}]", name, i)); 059 } 060 return list; 061 } 062 063 /** 064 * Check that a string is not null and not empty. If null or emtpy throws an IllegalArgumentException. 065 * 066 * @param str value. 067 * @param name parameter name for the exception message. 068 * @return the given value. 069 */ 070 public static String notEmpty(String str, String name) { 071 return notEmpty(str, name, null); 072 } 073 074 /** 075 * Check that a string is not null and not empty. If null or emtpy throws an IllegalArgumentException. 076 * 077 * @param str value. 078 * @param name parameter name for the exception message. 079 * @param info additional information to be printed with the exception message 080 * @return the given value. 081 */ 082 public static String notEmpty(String str, String name, String info) { 083 if (str == null) { 084 throw new IllegalArgumentException(name + " cannot be null" + (info == null ? "" : ", " + info)); 085 } 086 if (str.length() == 0) { 087 throw new IllegalArgumentException(name + " cannot be empty" + (info == null ? "" : ", " + info)); 088 } 089 return str; 090 } 091 092 /** 093 * Check that a list is not null and that none of its elements is null. If null or if the list has emtpy elements 094 * throws an IllegalArgumentException. 095 * 096 * @param list the list of strings. 097 * @param name parameter name for the exception message. 098 * @return the given list. 099 */ 100 public static List<String> notEmptyElements(List<String> list, String name) { 101 notNull(list, name); 102 for (int i = 0; i < list.size(); i++) { 103 notEmpty(list.get(i), XLog.format("list [{0}] element [{1}]", name, i)); 104 } 105 return list; 106 } 107 108 private static final int MAX_NODE_NAME_LEN = 50; 109 110 /** 111 * Check that the given string is a valid action name [a-zA-Z_][0-9a-zA-Z_\-]* and not longer than 50 chars. 112 * 113 * @param actionName string to validate is a token. 114 * @return the given string. 115 */ 116 public static String validateActionName(String actionName) { 117 ParamChecker.notEmpty(actionName, "action name"); 118 if (actionName.length() > MAX_NODE_NAME_LEN) { 119 throw new IllegalArgumentException(XLog.format("name [{0}] must be {1} chars or less", actionName, 120 MAX_NODE_NAME_LEN)); 121 } 122 123 char c = actionName.charAt(0); 124 if (!(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c == '_')) { 125 throw new IllegalArgumentException(XLog.format("name [{0}], must start with [A-Za-z_]", actionName)); 126 } 127 for (int i = 1; i < actionName.length(); i++) { 128 c = actionName.charAt(i); 129 if (!(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') 130 && !(c == '_' || c == '-')) { 131 throw new IllegalArgumentException(XLog.format("name [{0}] must be [A-Za-z_][0-9A-Za-z_]*", actionName)); 132 } 133 } 134 return actionName; 135 } 136 137 /** 138 * Return if the specified token is a valid Java identifier. 139 * 140 * @param token string to validate if it is a valid Java identifier. 141 * @return if the specified token is a valid Java identifier. 142 */ 143 public static boolean isValidIdentifier(String token) { 144 ParamChecker.notEmpty(token, "identifier"); 145 for (int i = 0; i < token.length(); i++) { 146 char c = token.charAt(i); 147 if (!(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') && !(c == '_')) { 148 return false; 149 } 150 if (i == 0 && (c >= '0' && c <= '9')) { 151 return false; 152 } 153 } 154 return true; 155 } 156 157 /** 158 * Check whether the value is greater than or equals 0. 159 * 160 * @param value : value to test 161 * @param name : Name of the parameter 162 * @return If the value is > 0, return the value. Otherwise throw IllegalArgumentException 163 */ 164 public static int checkGTZero(int value, String name) { 165 if (value <= 0) { 166 throw new IllegalArgumentException(XLog.format("parameter [{0}] = [{1}] must be greater than zero", name, 167 value)); 168 } 169 return value; 170 } 171 172 /** 173 * Check whether the value is greater than or equals to 0. 174 * 175 * @param value : value to test 176 * @param name : Name of the parameter 177 * @return If the value is >= 0, return the value. Otherwise throw IllegalArgumentException 178 */ 179 public static int checkGEZero(int value, String name) { 180 if (value < 0) { 181 throw new IllegalArgumentException(XLog.format( 182 "parameter [{0}] = [{1}] must be greater than or equals zero", name, value)); 183 } 184 return value; 185 } 186 187 /** 188 * Check whether the value is less than or equal to 0. 189 * 190 * @param value : value to test 191 * @param name : Name of the parameter 192 * @return If the value is <= 0, return the value. Otherwise throw IllegalArgumentException 193 */ 194 public static int checkLEZero(int value, String name) { 195 if (value > 0) { 196 throw new IllegalArgumentException(XLog.format( 197 "parameter [{0}] = [{1}] must be less than or equal to zero", name, value)); 198 } 199 return value; 200 } 201 202 /** 203 * Check whether the value is Integer. 204 * 205 * @param value : value to test 206 * @param name : Name of the parameter 207 * @return If the value is integer, return the value. Otherwise throw IllegalArgumentException 208 */ 209 public static int checkInteger(String val, String name) { 210 int ret; 211 try { 212 ret = Integer.parseInt(val); 213 } 214 catch (NumberFormatException nex) { 215 throw new IllegalArgumentException(XLog.format( 216 "parameter [{0}] = [{1}] must be an integer. Parsing error {2}", name, val, nex.getMessage(), nex)); 217 } 218 return ret; 219 } 220 221 /** 222 * Check whether a value is a valid coordinator frequency. 223 * 224 * @param value : value to test 225 * @return If the value is a valid frequency, return the frequency, Otherwise throw IllegalArgumentException 226 */ 227 public static String checkFrequency(String val) { 228 try { 229 Integer.parseInt(val); 230 } 231 catch (NumberFormatException ex) { 232 try { 233 // this part is necessary since Quartz 234 // doesn't support for specifying both a day-of-week 235 // and a day-of-month parameter, nor does it support 236 // using "?" in both fields, but we don't want to 237 // expose it to users. 238 String[] cronArray1 = val.split(" "); 239 String[] cronArray2 = val.split(" "); 240 241 if (cronArray1.length != 5) { 242 throw new IllegalArgumentException(XLog.format( 243 "parameter [{0}] = [{1}] must have 5 bit fields. Parsing error {2}", "frequency", 244 val, ex.getMessage(), ex)); 245 } 246 247 if (!cronArray1[4].trim().equals("?")) { 248 cronArray1[2] = "?"; 249 } 250 251 if (!cronArray2[2].trim().equals("?")) { 252 cronArray2[4] = "?"; 253 } 254 255 new CronExpression("0 " + StringUtils.join(cronArray1, " ")); 256 new CronExpression("0 " + StringUtils.join(cronArray2, " ")); 257 } 258 catch (ParseException pex) { 259 throw new IllegalArgumentException(XLog.format( 260 "parameter [{0}] = [{1}] must be an integer or a cron syntax. Parsing error {2}", "frequency", 261 val, ex.getMessage(), ex)); 262 } 263 } 264 return val; 265 } 266 /** 267 * Check whether the value is Oozie processing timezone data format. 268 * 269 * @param value : value to test 270 * @param name : Name of the parameter 271 * @return If the value is in Oozie processing timezone date format, return the value. 272 * Otherwise throw IllegalArgumentException 273 */ 274 public static Date checkDateOozieTZ(String date, String name) { 275 Date ret; 276 try { 277 ret = DateUtils.parseDateOozieTZ(date); 278 } 279 catch (Exception ex) { 280 throw new IllegalArgumentException(XLog.format( 281 "parameter [{0}] = [{1}] must be Date in {2} format ({3})." 282 + " Parsing error {4}", name, date, DateUtils.getOozieProcessingTimeZone().getID(), 283 DateUtils.getOozieTimeMask(), ex)); 284 } 285 return ret; 286 } 287 288 /** 289 * Check whether the value mention correct Timezone. 290 * 291 * @param value : value to test 292 * @param name : Name of the parameter 293 * @return If the value is correct TZ return the value. Otherwise throw IllegalArgumentException 294 */ 295 public static TimeZone checkTimeZone(String tzStr, String name) { 296 TimeZone tz; 297 try { 298 tz = DateUtils.getTimeZone(tzStr); 299 } 300 catch (Exception ex) { 301 throw new IllegalArgumentException(XLog.format("parameter [{0}] = [{1}] must be a valid TZ." 302 + " Parsing error {2}", name, tzStr, ex.getMessage(), ex)); 303 } 304 return tz; 305 } 306 307 /** 308 * Check whether an item is a member of an array of string 309 * 310 * @param item : item to test 311 * @param members : List of items in string 312 * @param name : Name of the parameter 313 * @return If the item is in the member return true. Otherwise throw IllegalArgumentException 314 */ 315 public static boolean isMember(String item, String[] members, String name) { 316 for (int i = 0; i < members.length; i++) { 317 if (members[i].equals(item)) { 318 return true; 319 } 320 } 321 // Error case 322 StringBuilder buff = new StringBuilder(); 323 for (int i = 0; i < members.length; i++) { 324 buff.append(members[i]).append(", "); 325 } 326 throw new IllegalArgumentException(XLog.format("parameter [{0}] = [{1}] " + "must be in the list {2}", name, 327 item, buff.toString())); 328 } 329}