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