001package com.nimbusds.infinispan.persistence.sql.config;
002
003
004import com.nimbusds.common.config.LoggableConfiguration;
005import com.nimbusds.infinispan.persistence.sql.Loggers;
006import com.nimbusds.infinispan.persistence.sql.SQLRecordTransformer;
007import com.nimbusds.infinispan.persistence.sql.SQLStore;
008import net.jcip.annotations.Immutable;
009import org.apache.commons.lang3.StringUtils;
010import org.infinispan.commons.configuration.BuiltBy;
011import org.infinispan.commons.configuration.ConfigurationFor;
012import org.infinispan.commons.configuration.attributes.Attribute;
013import org.infinispan.commons.configuration.attributes.AttributeDefinition;
014import org.infinispan.commons.configuration.attributes.AttributeSet;
015import org.infinispan.commons.util.StringPropertyReplacer;
016import org.infinispan.configuration.cache.AbstractStoreConfiguration;
017import org.infinispan.configuration.cache.AsyncStoreConfiguration;
018import org.jooq.SQLDialect;
019
020import java.util.Properties;
021
022
023/**
024 * SQL store configuration.
025 */
026@Immutable
027@BuiltBy(SQLStoreConfigurationBuilder.class)
028@ConfigurationFor(SQLStore.class)
029public class SQLStoreConfiguration extends AbstractStoreConfiguration implements LoggableConfiguration {
030        
031        
032        /**
033         * The attribute definition for the record transformer class.
034         */
035        static final AttributeDefinition<Class> RECORD_TRANSFORMER = AttributeDefinition.builder("recordTransformer", null, Class.class).build();
036        
037        
038        /**
039         * The attribute definition for the query executor class.
040         */
041        static final AttributeDefinition<Class> QUERY_EXECUTOR = AttributeDefinition.builder("queryExecutor", null, Class.class).build();
042        
043        
044        /**
045         * The attribute definition for the SQL dialect.
046         */
047        static final AttributeDefinition<SQLDialect> SQL_DIALECT = AttributeDefinition.builder("sqlDialect", SQLDialect.DEFAULT).build();
048        
049        
050        /**
051         * The attribute definition for the optional create table if missing
052         * setting.
053         */
054        static final AttributeDefinition<Boolean> CREATE_TABLE_IF_MISSING = AttributeDefinition.builder("createTableIfMissing", Boolean.TRUE).build();
055        
056        
057        /**
058         * The attribute definition for the optional create table ignore errors
059         * setting.
060         */
061        static final AttributeDefinition<Boolean> CREATE_TABLE_IGNORE_ERRORS = AttributeDefinition.builder("createTableIgnoreErrors", Boolean.FALSE).build();
062        
063        
064        /**
065         * The attribute definition for the optional connection pool reference.
066         */
067        static final AttributeDefinition<String> CONNECTION_POOL = AttributeDefinition.builder("connectionPool", null, String.class).build();
068
069
070        /**
071         * The attribute definition for the page limit in SQL queries to select
072         * expired records.
073         */
074        static final AttributeDefinition<Integer> EXPIRED_QUERY_PAGE_LIMIT = AttributeDefinition.builder("expiredQueryPageLimit", 250, Integer.class).build();
075        
076        
077        /**
078         * Returns the attribute definitions for the SQL store configuration.
079         *
080         * @return The attribute definitions.
081         */
082        public static AttributeSet attributeDefinitionSet() {
083                return new AttributeSet(SQLStoreConfiguration.class,
084                        AbstractStoreConfiguration.attributeDefinitionSet(),
085                        RECORD_TRANSFORMER,
086                        QUERY_EXECUTOR,
087                        SQL_DIALECT,
088                        CREATE_TABLE_IF_MISSING,
089                        CREATE_TABLE_IGNORE_ERRORS,
090                        CONNECTION_POOL,
091                        EXPIRED_QUERY_PAGE_LIMIT
092                );
093        }
094        
095        
096        /**
097         * The class for transforming between Infinispan entries (key / value
098         * pair and optional metadata) and a corresponding SQL record.
099         *
100         * <p>See {@link SQLRecordTransformer}.
101         */
102        private final Attribute<Class> recordTransformerClass;
103        
104        
105        /**
106         * The optional class for executing direct SQL queries against the
107         * database.
108         *
109         * <p>See {@link com.nimbusds.infinispan.persistence.common.query.QueryExecutor}
110         */
111        private final Attribute<Class> queryExecutorClass;
112        
113        
114        /**
115         * The configured SQL dialect.
116         */
117        private final Attribute<SQLDialect> sqlDialect;
118        
119        
120        /**
121         * The configured optional create table if missing setting.
122         */
123        private final Attribute<Boolean> createTableIfMissing;
124        
125        
126        /**
127         * The configured optional create table ignore errors setting.
128         */
129        private final Attribute<Boolean> createTableIgnoreErrors;
130        
131        
132        /**
133         * The configured connection pool reference.
134         */
135        private final Attribute<String> connectionPool;
136
137
138        /**
139         * The configured page limit in SQL queries to select expired records.
140         */
141        private final Attribute<Integer> expiredQueryPageLimit;
142
143
144        /**
145         * Creates a new SQL store configuration.
146         *
147         * @param attributes  The configuration attributes. Must not be
148         *                    {@code null}.
149         * @param asyncConfig Configuration for the async cache loader.
150         */
151        public SQLStoreConfiguration(final AttributeSet attributes,
152                                     final AsyncStoreConfiguration asyncConfig) {
153
154                super(attributes, asyncConfig);
155                
156                recordTransformerClass = attributes.attribute(RECORD_TRANSFORMER);
157                assert recordTransformerClass != null;
158                
159                queryExecutorClass = attributes.attribute(QUERY_EXECUTOR);
160                
161                sqlDialect = attributes.attribute(SQL_DIALECT);
162                assert sqlDialect != null;
163                
164                createTableIfMissing = attributes.attribute(CREATE_TABLE_IF_MISSING);
165                
166                createTableIgnoreErrors = attributes.attribute(CREATE_TABLE_IGNORE_ERRORS);
167                
168                connectionPool = attributes.attribute(CONNECTION_POOL);
169
170                expiredQueryPageLimit = attributes.attribute(EXPIRED_QUERY_PAGE_LIMIT);
171        }
172        
173        
174        /**
175         * Returns the class for transforming between Infinispan entries (key /
176         * value pairs and optional metadata) and a corresponding SQL record.
177         *
178         * <p>See {@link SQLRecordTransformer}.
179         *
180         * @return The record transformer class.
181         */
182        public Class getRecordTransformerClass() {
183                
184                return recordTransformerClass.get();
185        }
186        
187        
188        /**
189         * Returns the optional class for executing direct SQL queries against
190         * the database.
191         *
192         * <p>See {@link com.nimbusds.infinispan.persistence.common.query.QueryExecutor}
193         *
194         * @return The query executor class, {@code null} if not specified.
195         */
196        public Class getQueryExecutorClass() {
197                
198                return queryExecutorClass.get();
199        }
200        
201        
202        /**
203         * Returns the configured SQL dialect.
204         *
205         * @return The SQL dialect.
206         */
207        public SQLDialect getSQLDialect() {
208                
209                return sqlDialect.get();
210        }
211        
212        
213        /**
214         * Returns the configured create table if missing setting.
215         *
216         * @return {@code true} to create the underlying table(s) if missing,
217         *         {@code false} to skip this check.
218         */
219        public boolean createTableIfMissing() {
220                
221                return createTableIfMissing.get();
222        }
223        
224        
225        /**
226         * Returns the configured create table ignore error setting.
227         *
228         * @return {@code true} to ignore create table errors, {@code false} to
229         *         treat them as fatal.
230         */
231        public boolean createTableIgnoreErrors() {
232                
233                return createTableIgnoreErrors.get();
234        }
235        
236        
237        /**
238         * Returns the configured connection pool reference.
239         *
240         * @return The connection pool reference, {@code null} if none.
241         */
242        public String getConnectionPool() {
243                
244                return connectionPool.get();
245        }
246
247
248        /**
249         * Returns the configured page limit in SQL queries to select expired
250         * records.
251         *
252         * @return The page limit in SQL queries to select expired records.
253         */
254        public int getExpiredQueryPageLimit() {
255
256                return expiredQueryPageLimit.get();
257        }
258
259
260        @Override
261        public Properties properties() {
262                
263                // Interpolate with system properties where ${sysPropName} is found
264                
265                var interpolatedProps = new Properties();
266                
267                for (String name: super.properties().stringPropertyNames()) {
268                        interpolatedProps.setProperty(name, StringPropertyReplacer.replaceProperties(super.properties().getProperty(name)));
269                }
270                
271                return interpolatedProps;
272        }
273        
274        
275        @Override
276        public void log() {
277                
278                Loggers.MAIN_LOG.info("[IS0000] Infinispan SQL store: Record transformer class: {} ", getRecordTransformerClass().getCanonicalName());
279                Loggers.MAIN_LOG.info("[IS0001] Infinispan SQL store: Query executor class: {} ", getQueryExecutorClass() != null ? getQueryExecutorClass().getCanonicalName() : "not specified");
280                Loggers.MAIN_LOG.info("[IS0002] Infinispan SQL store: SQL dialect: {} ", sqlDialect);
281                Loggers.MAIN_LOG.info("[IS0004] Infinispan SQL store: Create table if missing: {} ", createTableIfMissing);
282                if (createTableIfMissing.get()) {
283                        Loggers.MAIN_LOG.info("[IS0009] Infinispan SQL store: Create table ignore errors: {} ", createTableIgnoreErrors);
284                }
285                Loggers.MAIN_LOG.info("[IS0008] Infinispan SQL store: Connection pool reference: {} ", getConnectionPool() != null ? getConnectionPool() : "not specified");
286
287                Loggers.MAIN_LOG.info("[IS0010] Infinispan SQL store: Expired record select query page limit: {}" , getExpiredQueryPageLimit());
288                
289                if (StringUtils.isNotBlank(properties().getProperty("dataSourceClassName"))) {
290                        Loggers.MAIN_LOG.info("[IS0005] Infinispan SQL store: Data source class name: {} ", properties().getProperty("dataSourceClassName"));
291                }
292                
293                if (StringUtils.isNotBlank(properties().getProperty("dataSource.url"))) {
294                        Loggers.MAIN_LOG.info("[IS0006] Infinispan SQL store: Data source URL: {} ", properties().getProperty("dataSource.url"));
295                }
296                
297                // Old style JDBC URL config
298                if (StringUtils.isNotBlank(properties().getProperty("jdbcUrl"))) {
299                        Loggers.MAIN_LOG.info("[IS0003] Infinispan SQL store: JDBC URL: {} ", properties().getProperty("jdbcUrl"));
300                }
301        }
302}