View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbcp2;
18  
19  import java.sql.Connection;
20  import java.sql.ResultSet;
21  import java.sql.Statement;
22  import java.text.MessageFormat;
23  import java.time.Duration;
24  import java.time.Instant;
25  import java.util.Collection;
26  import java.util.HashSet;
27  import java.util.Properties;
28  import java.util.ResourceBundle;
29  import java.util.Set;
30  import java.util.function.Consumer;
31  
32  import org.apache.commons.pool2.PooledObject;
33  
34  /**
35   * Utility methods.
36   *
37   * @since 2.0
38   */
39  public final class Utils {
40  
41      private static final ResourceBundle messages = ResourceBundle
42          .getBundle(Utils.class.getPackage().getName() + ".LocalStrings");
43  
44      /**
45       * Whether the security manager is enabled.
46       *
47       * @deprecated No replacement.
48       */
49      @Deprecated
50      public static final boolean IS_SECURITY_ENABLED = isSecurityEnabled();
51  
52      /** Any SQL_STATE starting with this value is considered a fatal disconnect */
53      public static final String DISCONNECTION_SQL_CODE_PREFIX = "08";
54  
55      /**
56       * SQL codes of fatal connection errors.
57       * <ul>
58       * <li>57P01 (Admin shutdown)</li>
59       * <li>57P02 (Crash shutdown)</li>
60       * <li>57P03 (Cannot connect now)</li>
61       * <li>01002 (SQL92 disconnect error)</li>
62       * <li>JZ0C0 (Sybase disconnect error)</li>
63       * <li>JZ0C1 (Sybase disconnect error)</li>
64       * </ul>
65       * @deprecated Use {@link #getDisconnectionSqlCodes()}.
66       */
67      @Deprecated
68      public static final Set<String> DISCONNECTION_SQL_CODES;
69  
70      static final ResultSet[] EMPTY_RESULT_SET_ARRAY = {};
71  
72      static final String[] EMPTY_STRING_ARRAY = {};
73      static {
74          DISCONNECTION_SQL_CODES = new HashSet<>();
75          DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown
76          DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown
77          DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now
78          DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error
79          DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error
80          DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error
81      }
82  
83      /**
84       * Clones the given char[] if not null.
85       *
86       * @param value may be null.
87       * @return a cloned char[] or null.
88       */
89      public static char[] clone(final char[] value) {
90          return value == null ? null : value.clone();
91      }
92  
93      /**
94       * Clones the given {@link Properties} without the standard "user" or "password" entries.
95       *
96       * @param properties may be null
97       * @return a clone of the input without the standard "user" or "password" entries.
98       * @since 2.8.0
99       */
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 }