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 *
017 */
018
019package org.apache.commons.dbcp2;
020
021import java.sql.Connection;
022import java.sql.ResultSet;
023import java.sql.Statement;
024import java.text.MessageFormat;
025import java.util.HashSet;
026import java.util.Properties;
027import java.util.ResourceBundle;
028import java.util.Set;
029
030/**
031 * Utility methods.
032 *
033 * @since 2.0
034 */
035public final class Utils {
036
037    private static final ResourceBundle messages = ResourceBundle
038        .getBundle(Utils.class.getPackage().getName() + ".LocalStrings");
039
040    /**
041     * Whether the security manager is enabled.
042     * 
043     * @deprecated No replacement.
044     */
045    @Deprecated
046    public static final boolean IS_SECURITY_ENABLED = isSecurityEnabled();
047
048    /** Any SQL_STATE starting with this value is considered a fatal disconnect */
049    public static final String DISCONNECTION_SQL_CODE_PREFIX = "08";
050
051    /**
052     * SQL codes of fatal connection errors.
053     * <ul>
054     * <li>57P01 (Admin shutdown)</li>
055     * <li>57P02 (Crash shutdown)</li>
056     * <li>57P03 (Cannot connect now)</li>
057     * <li>01002 (SQL92 disconnect error)</li>
058     * <li>JZ0C0 (Sybase disconnect error)</li>
059     * <li>JZ0C1 (Sybase disconnect error)</li>
060     * </ul>
061     */
062    public static final Set<String> DISCONNECTION_SQL_CODES;
063
064    static final ResultSet[] EMPTY_RESULT_SET_ARRAY = {};
065
066    static final String[] EMPTY_STRING_ARRAY = {};
067    static {
068        DISCONNECTION_SQL_CODES = new HashSet<>();
069        DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown
070        DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown
071        DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now
072        DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error
073        DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error
074        DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error
075    }
076
077    /**
078     * Clones the given char[] if not null.
079     *
080     * @param value may be null.
081     * @return a cloned char[] or null.
082     */
083    public static char[] clone(final char[] value) {
084        return value == null ? null : value.clone();
085    }
086
087    /**
088     * Clones the given {@link Properties} without the standard "user" or "password" entries.
089     *
090     * @param properties may be null
091     * @return a clone of the input without the standard "user" or "password" entries.
092     * @since 2.8.0
093     */
094    public static Properties cloneWithoutCredentials(final Properties properties) {
095        if (properties != null) {
096            final Properties temp = (Properties) properties.clone();
097            temp.remove(Constants.KEY_USER);
098            temp.remove(Constants.KEY_PASSWORD);
099            return temp;
100        }
101        return properties;
102    }
103
104    /**
105     * Closes the AutoCloseable (which may be null).
106     *
107     * @param autoCloseable an AutoCloseable, may be {@code null}
108     * @since 2.6.0
109     */
110    public static void closeQuietly(final AutoCloseable autoCloseable) {
111        if (autoCloseable != null) {
112            try {
113                autoCloseable.close();
114            } catch (final Exception e) {
115                // ignored
116            }
117        }
118    }
119
120    /**
121     * Closes the Connection (which may be null).
122     *
123     * @param connection a Connection, may be {@code null}
124     * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
125     */
126    @Deprecated
127    public static void closeQuietly(final Connection connection) {
128        if (connection != null) {
129            try {
130                connection.close();
131            } catch (final Exception e) {
132                // ignored
133            }
134        }
135    }
136
137    /**
138     * Closes the ResultSet (which may be null).
139     *
140     * @param resultSet a ResultSet, may be {@code null}
141     * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
142     */
143    @Deprecated
144    public static void closeQuietly(final ResultSet resultSet) {
145        if (resultSet != null) {
146            try {
147                resultSet.close();
148            } catch (final Exception e) {
149                // ignored
150            }
151        }
152    }
153
154    /**
155     * Closes the Statement (which may be null).
156     *
157     * @param statement a Statement, may be {@code null}.
158     * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
159     */
160    @Deprecated
161    public static void closeQuietly(final Statement statement) {
162        if (statement != null) {
163            try {
164                statement.close();
165            } catch (final Exception e) {
166                // ignored
167            }
168        }
169    }
170
171    /**
172     * Gets the correct i18n message for the given key.
173     *
174     * @param key The key to look up an i18n message.
175     * @return The i18n message.
176     */
177    public static String getMessage(final String key) {
178        return getMessage(key, (Object[]) null);
179    }
180
181    /**
182     * Gets the correct i18n message for the given key with placeholders replaced by the supplied arguments.
183     *
184     * @param key A message key.
185     * @param args The message arguments.
186     * @return An i18n message.
187     */
188    public static String getMessage(final String key, final Object... args) {
189        final String msg = messages.getString(key);
190        if (args == null || args.length == 0) {
191            return msg;
192        }
193        final MessageFormat mf = new MessageFormat(msg);
194        return mf.format(args, new StringBuffer(), null).toString();
195    }
196
197    static boolean isSecurityEnabled() {
198        return System.getSecurityManager() != null;
199    }
200
201    /**
202     * Converts the given String to a char[].
203     *
204     * @param value may be null.
205     * @return a char[] or null.
206     */
207    public static char[] toCharArray(final String value) {
208        return value != null ? value.toCharArray() : null;
209    }
210
211    /**
212     * Converts the given char[] to a String.
213     *
214     * @param value may be null.
215     * @return a String or null.
216     */
217    public static String toString(final char[] value) {
218        return value == null ? null : String.valueOf(value);
219    }
220
221    private Utils() {
222        // not instantiable
223    }
224
225}