001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015-2016 ForgeRock AS. 015 */ 016package org.forgerock.util; 017 018import java.io.Closeable; 019import java.io.IOException; 020import java.util.Arrays; 021import java.util.Iterator; 022import java.util.concurrent.ThreadFactory; 023import java.util.concurrent.atomic.AtomicInteger; 024 025/** 026 * Common utility methods. 027 */ 028public final class Utils { 029 030 /** 031 * Closes the provided resources ignoring any errors which occurred. 032 * 033 * @param resources 034 * The resources to be closed, which may be {@code null}. 035 */ 036 public static void closeSilently(final Closeable... resources) { 037 if (resources == null) { 038 return; 039 } 040 closeSilently(Arrays.asList(resources)); 041 } 042 043 /** 044 * Closes the provided resources ignoring any errors which occurred. 045 * 046 * @param resources 047 * The resources to be closed, which may be {@code null}. 048 */ 049 public static void closeSilently(final Iterable<? extends Closeable> resources) { 050 if (resources == null) { 051 return; 052 } 053 for (final Closeable r : resources) { 054 try { 055 if (r != null) { 056 r.close(); 057 } 058 } catch (final IOException ignored) { 059 // Ignore. 060 } 061 } 062 } 063 064 /** 065 * Returns a string whose content is the string representation of the 066 * provided objects concatenated together using the provided separator. 067 * 068 * @param separator 069 * The separator string. 070 * @param values 071 * The objects to be joined. 072 * @return A string whose content is the string representation of the 073 * provided objects concatenated together using the provided 074 * separator. 075 * @throws NullPointerException 076 * If {@code values} or {@code separator} were {@code null}. 077 */ 078 public static String joinAsString(final String separator, final Object... values) { 079 return joinAsString(separator, Arrays.asList(values)); 080 } 081 082 /** 083 * Returns a string whose content is the string representation of the 084 * objects contained in the provided iterable concatenated together using 085 * the provided separator. 086 * 087 * @param separator 088 * The separator string. 089 * @param values 090 * The iterable whose elements are to be joined. 091 * @return A string whose content is the string representation of the 092 * objects contained in the provided iterable concatenated 093 * together using the provided separator. 094 * @throws NullPointerException 095 * If {@code separator} or {@code values} were {@code null}. 096 */ 097 public static String joinAsString(final String separator, final Iterable<?> values) { 098 Reject.ifNull(separator); 099 Reject.ifNull(values); 100 101 final StringBuilder builder = new StringBuilder(); 102 joinAsString(builder, separator, values); 103 return builder.toString(); 104 } 105 106 /** 107 * Appends into the provided {@link StringBuilder} the string representation 108 * of the provided objects concatenated together using the provided separator. 109 * 110 * @param builder 111 * The String builder where to append. 112 * @param separator 113 * The separator string. 114 * @param values 115 * The objects to be joined. 116 * @throws NullPointerException 117 * If {@code builder}, {@code separator} or {@code values} were {@code null}. 118 */ 119 public static void joinAsString(final StringBuilder builder, final String separator, final Object... values) { 120 joinAsString(builder, separator, Arrays.asList(values)); 121 } 122 123 /** 124 * Appends into the provided {@link StringBuilder} the string representation 125 * of the objects contained in the provided iterable concatenated together 126 * using the provided separator. 127 * 128 * @param builder 129 * The String builder where to append. 130 * @param separator 131 * The separator string. 132 * @param values 133 * The iterable whose elements are to be joined. 134 * @throws NullPointerException 135 * If {@code builder}, {@code separator} or {@code values} were {@code null}. 136 */ 137 public static void joinAsString(final StringBuilder builder, final String separator, final Iterable<?> values) { 138 Reject.ifNull(builder); 139 Reject.ifNull(separator); 140 Reject.ifNull(values); 141 142 final Iterator<?> iterator = values.iterator(); 143 if (iterator.hasNext()) { 144 builder.append(iterator.next()); 145 146 while (iterator.hasNext()) { 147 builder.append(separator); 148 builder.append(iterator.next()); 149 } 150 } 151 } 152 153 /** 154 * Creates a new thread factory which will create threads using the 155 * specified thread group, naming template, and daemon status. 156 * 157 * @param group 158 * The thread group, which may be {@code null}. 159 * @param nameTemplate 160 * The thread name format string which may contain a "%d" format 161 * option which will be substituted with the thread count. 162 * @param isDaemon 163 * Indicates whether or not threads should be daemon threads. 164 * @return The new thread factory. 165 */ 166 public static ThreadFactory newThreadFactory(final ThreadGroup group, 167 final String nameTemplate, final boolean isDaemon) { 168 return new ThreadFactory() { 169 private final AtomicInteger count = new AtomicInteger(); 170 171 @Override 172 public Thread newThread(final Runnable r) { 173 final String name = String.format(nameTemplate, count.getAndIncrement()); 174 final Thread t = new Thread(group, r, name); 175 t.setDaemon(isDaemon); 176 return t; 177 } 178 }; 179 } 180 181 /** 182 * Returns the string value as an enum constant of the specified enum 183 * type. The string value and enum constants are compared, ignoring case 184 * considerations. If the string value is {@code null}, this method returns 185 * {@code null}. 186 * 187 * @param <T> 188 * the enum type sub-class. 189 * @param value 190 * the string value 191 * @param type 192 * the enum type to match constants with the value. 193 * @return the enum constant represented by the string value. 194 * @throws IllegalArgumentException 195 * if {@code type} does not represent an enum type, 196 * of if {@code value} does not match one of the enum constants 197 * @throws NullPointerException 198 * if {@code type} is {@code null}. 199 */ 200 public static <T extends Enum<T>> T asEnum(final String value, final Class<T> type) { 201 if (value == null) { 202 return null; 203 } 204 final T[] constants = type.getEnumConstants(); 205 if (constants == null) { 206 throw new IllegalArgumentException("Type is not an enum class"); 207 } 208 for (final T constant : constants) { 209 if (value.equalsIgnoreCase(constant.toString())) { 210 return constant; 211 } 212 } 213 final StringBuilder sb = new StringBuilder("Expecting String containing one of: "); 214 sb.append(joinAsString(" ", (Object[]) constants)); 215 throw new IllegalArgumentException(sb.toString()); 216 } 217 218 /** 219 * Check to see if the provided String is {@code null} or empty. 220 * @param value The value to check. 221 * @return {@code true} if the value is either {@code null} or is empty. 222 */ 223 public static boolean isNullOrEmpty(String value) { 224 return value == null || value.isEmpty(); 225 } 226 227 /** 228 * Check to see if a character sequence is null or blank. 229 * 230 * @param charSeq Sequence to test (String is also a CharSequence) 231 * @return true if the char sequence is null or blank. 232 */ 233 public static boolean isBlank(CharSequence charSeq) { 234 if (charSeq == null) { 235 return true; 236 } 237 final int length = charSeq.length(); 238 for (int i = 0; i < length; i++) { 239 if (!Character.isWhitespace(charSeq.charAt(i))) { 240 return false; 241 } 242 } 243 return true; 244 } 245 246 247 private Utils() { 248 // Prevent instantiation. 249 } 250}