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