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