001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.dbcp2; 018 019import java.sql.Connection; 020import java.sql.ResultSet; 021import java.sql.Statement; 022import java.text.MessageFormat; 023import java.time.Duration; 024import java.time.Instant; 025import java.util.Collection; 026import java.util.HashSet; 027import java.util.Properties; 028import java.util.ResourceBundle; 029import java.util.Set; 030import java.util.function.Consumer; 031 032import org.apache.commons.pool2.PooledObject; 033 034/** 035 * Utility methods. 036 * 037 * @since 2.0 038 */ 039public final class Utils { 040 041 private static final ResourceBundle messages = ResourceBundle 042 .getBundle(Utils.class.getPackage().getName() + ".LocalStrings"); 043 044 /** 045 * Whether the security manager is enabled. 046 * 047 * @deprecated No replacement. 048 */ 049 @Deprecated 050 public static final boolean IS_SECURITY_ENABLED = isSecurityEnabled(); 051 052 /** Any SQL_STATE starting with this value is considered a fatal disconnect */ 053 public static final String DISCONNECTION_SQL_CODE_PREFIX = "08"; 054 055 /** 056 * SQL codes of fatal connection errors. 057 * <ul> 058 * <li>57P01 (Admin shutdown)</li> 059 * <li>57P02 (Crash shutdown)</li> 060 * <li>57P03 (Cannot connect now)</li> 061 * <li>01002 (SQL92 disconnect error)</li> 062 * <li>JZ0C0 (Sybase disconnect error)</li> 063 * <li>JZ0C1 (Sybase disconnect error)</li> 064 * </ul> 065 * @deprecated Use {@link #getDisconnectionSqlCodes()}. 066 */ 067 @Deprecated 068 public static final Set<String> DISCONNECTION_SQL_CODES; 069 070 static final ResultSet[] EMPTY_RESULT_SET_ARRAY = {}; 071 072 static final String[] EMPTY_STRING_ARRAY = {}; 073 static { 074 DISCONNECTION_SQL_CODES = new HashSet<>(); 075 DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown 076 DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown 077 DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now 078 DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error 079 DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error 080 DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error 081 } 082 083 /** 084 * Clones the given char[] if not null. 085 * 086 * @param value may be null. 087 * @return a cloned char[] or null. 088 */ 089 public static char[] clone(final char[] value) { 090 return value == null ? null : value.clone(); 091 } 092 093 /** 094 * Clones the given {@link Properties} without the standard "user" or "password" entries. 095 * 096 * @param properties may be null 097 * @return a clone of the input without the standard "user" or "password" entries. 098 * @since 2.8.0 099 */ 100 public static Properties cloneWithoutCredentials(final Properties properties) { 101 if (properties != null) { 102 final Properties temp = (Properties) properties.clone(); 103 temp.remove(Constants.KEY_USER); 104 temp.remove(Constants.KEY_PASSWORD); 105 return temp; 106 } 107 return properties; 108 } 109 110 /** 111 * Closes the given {@link AutoCloseable} and if an exception is caught, then calls {@code exceptionHandler}. 112 * 113 * @param autoCloseable The resource to close. 114 * @param exceptionHandler Consumes exception thrown closing this resource. 115 * @since 2.10.0 116 */ 117 public static void close(final AutoCloseable autoCloseable, final Consumer<Exception> exceptionHandler) { 118 if (autoCloseable != null) { 119 try { 120 autoCloseable.close(); 121 } catch (final Exception e) { 122 if (exceptionHandler != null) { 123 exceptionHandler.accept(e); 124 } 125 } 126 } 127 } 128 129 /** 130 * Closes the AutoCloseable (which may be null). 131 * 132 * @param autoCloseable an AutoCloseable, may be {@code null} 133 * @since 2.6.0 134 */ 135 public static void closeQuietly(final AutoCloseable autoCloseable) { 136 close(autoCloseable, null); 137 } 138 139 /** 140 * Closes the Connection (which may be null). 141 * 142 * @param connection a Connection, may be {@code null} 143 * @deprecated Use {@link #closeQuietly(AutoCloseable)}. 144 */ 145 @Deprecated 146 public static void closeQuietly(final Connection connection) { 147 closeQuietly((AutoCloseable) connection); 148 } 149 150 /** 151 * Closes the ResultSet (which may be null). 152 * 153 * @param resultSet a ResultSet, may be {@code null} 154 * @deprecated Use {@link #closeQuietly(AutoCloseable)}. 155 */ 156 @Deprecated 157 public static void closeQuietly(final ResultSet resultSet) { 158 closeQuietly((AutoCloseable) resultSet); 159 } 160 161 /** 162 * Closes the Statement (which may be null). 163 * 164 * @param statement a Statement, may be {@code null}. 165 * @deprecated Use {@link #closeQuietly(AutoCloseable)}. 166 */ 167 @Deprecated 168 public static void closeQuietly(final Statement statement) { 169 closeQuietly((AutoCloseable) statement); 170 } 171 172 /** 173 * Gets a copy of SQL codes of fatal connection errors. 174 * <ul> 175 * <li>57P01 (Admin shutdown)</li> 176 * <li>57P02 (Crash shutdown)</li> 177 * <li>57P03 (Cannot connect now)</li> 178 * <li>01002 (SQL92 disconnect error)</li> 179 * <li>JZ0C0 (Sybase disconnect error)</li> 180 * <li>JZ0C1 (Sybase disconnect error)</li> 181 * </ul> 182 * @return SQL codes of fatal connection errors. 183 * @since 2.10.0 184 */ 185 public static Set<String> getDisconnectionSqlCodes() { 186 return new HashSet<>(DISCONNECTION_SQL_CODES); 187 } 188 189 /** 190 * Gets the correct i18n message for the given key. 191 * 192 * @param key The key to look up an i18n message. 193 * @return The i18n message. 194 */ 195 public static String getMessage(final String key) { 196 return getMessage(key, (Object[]) null); 197 } 198 199 /** 200 * Gets the correct i18n message for the given key with placeholders replaced by the supplied arguments. 201 * 202 * @param key A message key. 203 * @param args The message arguments. 204 * @return An i18n message. 205 */ 206 public static String getMessage(final String key, final Object... args) { 207 final String msg = messages.getString(key); 208 if (args == null || args.length == 0) { 209 return msg; 210 } 211 final MessageFormat mf = new MessageFormat(msg); 212 return mf.format(args, new StringBuffer(), null).toString(); 213 } 214 215 static boolean isEmpty(final Collection<?> collection) { 216 return collection == null || collection.isEmpty(); 217 } 218 219 static boolean isSecurityEnabled() { 220 return System.getSecurityManager() != null; 221 } 222 223 /** 224 * Converts the given String to a char[]. 225 * 226 * @param value may be null. 227 * @return a char[] or null. 228 */ 229 public static char[] toCharArray(final String value) { 230 return value != null ? value.toCharArray() : null; 231 } 232 233 /** 234 * Converts the given char[] to a String. 235 * 236 * @param value may be null. 237 * @return a String or null. 238 */ 239 public static String toString(final char[] value) { 240 return value == null ? null : String.valueOf(value); 241 } 242 243 public static void validateLifetime(final PooledObject<?> p, final Duration maxDuration) throws LifetimeExceededException { 244 if (maxDuration.compareTo(Duration.ZERO) > 0) { 245 final Duration lifetimeDuration = Duration.between(p.getCreateInstant(), Instant.now()); 246 if (lifetimeDuration.compareTo(maxDuration) > 0) { 247 throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded", lifetimeDuration, maxDuration)); 248 } 249 } 250 } 251 252 private Utils() { 253 // not instantiable 254 } 255 256}