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