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
018package org.apache.logging.log4j.core.appender.db.jdbc;
019
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.List;
023
024import org.apache.commons.dbcp2.PoolableConnectionFactory;
025import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
026import org.apache.logging.log4j.core.Core;
027import org.apache.logging.log4j.core.config.plugins.Plugin;
028import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
029import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
030import org.apache.logging.log4j.core.config.plugins.PluginElement;
031import org.apache.logging.log4j.status.StatusLogger;
032import org.apache.logging.log4j.util.Strings;
033
034/**
035 * Configures an Apache Commons DBCP {@link PoolableConnectionFactory}.
036 *
037 * @since 2.11.2
038 */
039@Plugin(name = "PoolableConnectionFactory", category = Core.CATEGORY_NAME, printObject = true)
040public class PoolableConnectionFactoryConfig {
041
042    public static class Builder implements org.apache.logging.log4j.core.util.Builder<PoolableConnectionFactoryConfig> {
043
044        private static final PoolableConnectionFactory DEFAULT = new PoolableConnectionFactory(null, null);
045
046        /**
047         * Internal constant to indicate the level is not set.
048         */
049        private static final int UNKNOWN_TRANSACTION_ISOLATION = -1;
050
051        // All of these instance variables match DBCP WRT Boolean vs. boolean.
052        // All of these defaults are the same as in PoolableConnectionFactory.
053
054        @PluginBuilderAttribute
055        private boolean cacheState;
056
057        // TODO
058        @PluginElement("ConnectionInitSqls")
059        private String[] connectionInitSqls;
060
061        @PluginBuilderAttribute
062        private Boolean defaultAutoCommit;
063
064        @PluginBuilderAttribute
065        private String defaultCatalog;
066
067        @PluginBuilderAttribute
068        private Integer defaultQueryTimeoutSeconds = DEFAULT.getDefaultQueryTimeout();
069
070        @PluginBuilderAttribute
071        private Boolean defaultReadOnly;
072
073        @PluginBuilderAttribute
074        private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION;
075
076        // TODO
077        @PluginElement("DisconnectionSqlCodes")
078        private String[] disconnectionSqlCodes = (String[]) (DEFAULT.getDisconnectionSqlCodes() == null ? null
079                : DEFAULT.getDisconnectionSqlCodes().toArray());
080
081        @PluginBuilderAttribute
082        private boolean autoCommitOnReturn = DEFAULT.isEnableAutoCommitOnReturn();
083
084        @PluginBuilderAttribute
085        private boolean fastFailValidation = DEFAULT.isFastFailValidation();
086
087        @PluginBuilderAttribute
088        private long maxConnLifetimeMillis = -1;
089
090        @PluginBuilderAttribute
091        private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
092
093        @PluginBuilderAttribute
094        private boolean poolStatements;
095
096        @PluginBuilderAttribute
097        private boolean rollbackOnReturn = DEFAULT.isRollbackOnReturn();
098
099        @PluginBuilderAttribute
100        private String validationQuery;
101
102        @PluginBuilderAttribute
103        private int validationQueryTimeoutSeconds = -1;
104
105        private List<String> asList(final String[] array) {
106            return array == null ? null : Arrays.asList(array);
107        }
108
109        @Override
110        public PoolableConnectionFactoryConfig build() {
111            return new PoolableConnectionFactoryConfig(cacheState, asList(connectionInitSqls), defaultAutoCommit,
112                    defaultCatalog, defaultQueryTimeoutSeconds, defaultReadOnly, defaultTransactionIsolation,
113                    asList(disconnectionSqlCodes), autoCommitOnReturn, fastFailValidation, maxConnLifetimeMillis,
114                    maxOpenPreparedStatements, poolStatements, rollbackOnReturn, validationQuery,
115                    validationQueryTimeoutSeconds);
116        }
117
118        public Builder setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
119            this.autoCommitOnReturn = autoCommitOnReturn;
120            return this;
121        }
122
123        public Builder setCacheState(final boolean cacheState) {
124            this.cacheState = cacheState;
125            return this;
126        }
127
128        public Builder setConnectionInitSqls(final String... connectionInitSqls) {
129            this.connectionInitSqls = connectionInitSqls;
130            return this;
131        }
132
133        public Builder setDefaultAutoCommit(final Boolean defaultAutoCommit) {
134            this.defaultAutoCommit = defaultAutoCommit;
135            return this;
136        }
137
138        public Builder setDefaultCatalog(final String defaultCatalog) {
139            this.defaultCatalog = defaultCatalog;
140            return this;
141        }
142
143        public Builder setDefaultQueryTimeoutSeconds(final Integer defaultQueryTimeoutSeconds) {
144            this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
145            return this;
146        }
147
148        public Builder setDefaultReadOnly(final Boolean defaultReadOnly) {
149            this.defaultReadOnly = defaultReadOnly;
150            return this;
151        }
152
153        public Builder setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
154            this.defaultTransactionIsolation = defaultTransactionIsolation;
155            return this;
156        }
157
158        public Builder setDisconnectionSqlCodes(final String... disconnectionSqlCodes) {
159            this.disconnectionSqlCodes = disconnectionSqlCodes;
160            return this;
161        }
162
163        public Builder setFastFailValidation(final boolean fastFailValidation) {
164            this.fastFailValidation = fastFailValidation;
165            return this;
166        }
167
168        public Builder setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
169            this.maxConnLifetimeMillis = maxConnLifetimeMillis;
170            return this;
171        }
172
173        public Builder setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
174            this.maxOpenPreparedStatements = maxOpenPreparedStatements;
175            return this;
176        }
177
178        public Builder setPoolStatements(final boolean poolStatements) {
179            this.poolStatements = poolStatements;
180            return this;
181        }
182
183        public Builder setRollbackOnReturn(final boolean rollbackOnReturn) {
184            this.rollbackOnReturn = rollbackOnReturn;
185            return this;
186        }
187
188        public Builder setValidationQuery(final String validationQuery) {
189            this.validationQuery = validationQuery;
190            return this;
191        }
192
193        public Builder setValidationQueryTimeoutSeconds(final int validationQueryTimeoutSeconds) {
194            this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
195            return this;
196        }
197    }
198
199    // ALL of these instance variables match DBCP WRT Boolean vs. boolean.
200
201    @PluginBuilderFactory
202    public static Builder newBuilder() {
203        return new Builder();
204    }
205
206    private final boolean cacheState;
207    private final Collection<String> connectionInitSqls;
208    private final Boolean defaultAutoCommit;
209    private final String defaultCatalog;
210    private final Integer defaultQueryTimeoutSeconds;
211    private final Boolean defaultReadOnly;
212    private final int defaultTransactionIsolation;
213    private final Collection<String> disconnectionSqlCodes;
214    private final boolean autoCommitOnReturn;
215    private final boolean fastFailValidation;
216    private final long maxConnLifetimeMillis;
217    private final int maxOpenPreparedStatements;
218    private final boolean poolStatements;
219    private final boolean rollbackOnReturn;
220    private final String validationQuery;
221
222    private final int validationQueryTimeoutSeconds;
223
224    private PoolableConnectionFactoryConfig(final boolean cacheState, final Collection<String> connectionInitSqls,
225            final Boolean defaultAutoCommit, final String defaultCatalog, final Integer defaultQueryTimeoutSeconds,
226            final Boolean defaultReadOnly, final int defaultTransactionIsolation,
227            final Collection<String> disconnectionSqlCodes, final boolean enableAutoCommitOnReturn,
228            final boolean fastFailValidation, final long maxConnLifetimeMillis, final int maxOpenPreparedStatements,
229            final boolean poolStatements, final boolean rollbackOnReturn, final String validationQuery,
230            final int validationQueryTimeoutSeconds) {
231        super();
232        this.cacheState = cacheState;
233        this.connectionInitSqls = connectionInitSqls;
234        this.defaultAutoCommit = defaultAutoCommit;
235        this.defaultCatalog = Strings.trimToNull(defaultCatalog);
236        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
237        this.defaultReadOnly = defaultReadOnly;
238        this.defaultTransactionIsolation = defaultTransactionIsolation;
239        this.disconnectionSqlCodes = disconnectionSqlCodes;
240        this.autoCommitOnReturn = enableAutoCommitOnReturn;
241        this.fastFailValidation = fastFailValidation;
242        this.maxConnLifetimeMillis = maxConnLifetimeMillis;
243        this.maxOpenPreparedStatements = maxOpenPreparedStatements;
244        this.poolStatements = poolStatements;
245        this.rollbackOnReturn = rollbackOnReturn;
246        this.validationQuery = Strings.trimToNull(validationQuery);
247        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
248    }
249
250    public void init(final PoolableConnectionFactory poolableConnectionFactory) {
251        if (poolableConnectionFactory != null) {
252            StatusLogger.getLogger().debug("Initializing PoolableConnectionFactory {} with {}",
253                    poolableConnectionFactory, this);
254            poolableConnectionFactory.setCacheState(cacheState);
255            poolableConnectionFactory.setConnectionInitSql(connectionInitSqls);
256            poolableConnectionFactory.setDefaultAutoCommit(defaultAutoCommit);
257            poolableConnectionFactory.setDefaultCatalog(defaultCatalog);
258            poolableConnectionFactory.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
259            poolableConnectionFactory.setDefaultReadOnly(defaultReadOnly);
260            poolableConnectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
261            poolableConnectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
262            poolableConnectionFactory.setEnableAutoCommitOnReturn(autoCommitOnReturn);
263            poolableConnectionFactory.setFastFailValidation(fastFailValidation);
264            poolableConnectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
265            poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
266            poolableConnectionFactory.setPoolStatements(poolStatements);
267            poolableConnectionFactory.setRollbackOnReturn(rollbackOnReturn);
268            poolableConnectionFactory.setValidationQuery(validationQuery);
269            poolableConnectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
270        }
271
272    }
273
274    @Override
275    public String toString() {
276        return String.format(
277                "PoolableConnectionFactoryConfig [cacheState=%s, connectionInitSqls=%s, defaultAutoCommit=%s, defaultCatalog=%s, defaultQueryTimeoutSeconds=%s, defaultReadOnly=%s, defaultTransactionIsolation=%s, disconnectionSqlCodes=%s, enableAutoCommitOnReturn=%s, fastFailValidation=%s, maxConnLifetimeMillis=%s, maxOpenPreparedStatements=%s, poolStatements=%s, rollbackOnReturn=%s, validationQuery=%s, validationQueryTimeoutSeconds=%s]",
278                cacheState, connectionInitSqls, defaultAutoCommit, defaultCatalog, defaultQueryTimeoutSeconds,
279                defaultReadOnly, defaultTransactionIsolation, disconnectionSqlCodes, autoCommitOnReturn,
280                fastFailValidation, maxConnLifetimeMillis, maxOpenPreparedStatements, poolStatements, rollbackOnReturn,
281                validationQuery, validationQueryTimeoutSeconds);
282    }
283
284}