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