/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.cache.store.jdbc;
import javax.cache.configuration.Factory;
import javax.sql.DataSource;
import org.apache.ignite.IgniteException;
import org.apache.ignite.cache.store.jdbc.dialect.JdbcDialect;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.IgniteComponentType;
import org.apache.ignite.internal.util.spring.IgniteSpringHelper;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.resources.SpringApplicationContextResource;
/**
* {@link Factory} implementation for {@link CacheJdbcPojoStore}.
*
* Use this factory to pass {@link CacheJdbcPojoStore} to {@link CacheConfiguration}.
* <p>
* Please note, that {@link CacheJdbcPojoStoreFactory#setDataSource(DataSource)} is deprecated and
* {@link CacheJdbcPojoStoreFactory#setDataSourceFactory(Factory)} or
* {@link CacheJdbcPojoStoreFactory#setDataSourceBean(String)} should be used instead.
*
* <h2 class="header">Spring Example</h2>
* <pre name="code" class="xml">
* <bean id= "myDataSource" class="org.h2.jdbcx.JdbcDataSource"/>
*
* <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
* ...
* <property name="cacheConfiguration">
* <list>
* <bean class="org.apache.ignite.configuration.CacheConfiguration">
* <property name="name" value="myCache" />
* ...
* <property name="cacheStoreFactory">
* <bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">
* <property name="dataSourceBean" value="myDataSource" />
* <property name="types">
* <list>
* <bean class="org.apache.ignite.cache.store.jdbc.JdbcType">
* <property name="cacheName" value="myCache" />
* <property name="databaseSchema" value="MY_DB_SCHEMA" />
* <property name="databaseTable" value="PERSON" />
* <property name="keyType" value="java.lang.Integer" />
* <property name="keyFields">
* <list>
* <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
* <property name="databaseFieldType" >
* <util:constant static-field="java.sql.Types.INTEGER"/>
* </property>
* <property name="databaseFieldName" value="ID" />
* <property name="javaFieldType" value="java.lang.Integer" />
* <property name="javaFieldName" value="id" />
* </bean>
* </list>
* </property>
* <property name="valueType" value="my.company.Person" />
* <property name="valueFields">
* <list>
* <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
* <property name="databaseFieldType" >
* <util:constant static-field="java.sql.Types.VARCHAR"/>
* </property>
* <property name="databaseFieldName" value="NAME" />
* <property name="javaFieldType" value="java.lang.String" />
* <property name="javaFieldName" value="name" />
* </bean>
* </list>
* </property>
* </bean>
* </list>
* </property>
* </bean>
* </property>
* </bean>
* </list>
* </property>
* </bean>
* </pre>
* <p>
* <img src="http://ignite.apache.org/images/spring-small.png">
* <br>
* For information about Spring framework visit <a href="http://www.springframework.org/">www.springframework.org</a>
*/
public class CacheJdbcPojoStoreFactory<K, V> implements Factory<CacheAbstractJdbcStore<K, V>> {
/** */
private static final long serialVersionUID = 0L;
/** Default value for write attempts. */
public static final int DFLT_WRITE_ATTEMPTS = 2;
/** Default batch size for put and remove operations. */
public static final int DFLT_BATCH_SIZE = 512;
/** Default batch size for put and remove operations. */
public static final int DFLT_PARALLEL_LOAD_CACHE_MINIMUM_THRESHOLD = 512;
/** Maximum batch size for writeAll and deleteAll operations. */
private int batchSize = DFLT_BATCH_SIZE;
/** Name of data source bean. */
private String dataSrcBean;
/** Database dialect. */
private JdbcDialect dialect;
/** Max workers thread count. These threads are responsible for load cache. */
private int maxPoolSize = Runtime.getRuntime().availableProcessors();
/** Maximum write attempts in case of database error. */
private int maxWrtAttempts = DFLT_WRITE_ATTEMPTS;
/** Parallel load cache minimum threshold. If {@code 0} then load sequentially. */
private int parallelLoadCacheMinThreshold = DFLT_PARALLEL_LOAD_CACHE_MINIMUM_THRESHOLD;
/** Hash calculator. */
private JdbcTypeHasher hasher = JdbcTypeDefaultHasher.INSTANCE;
/** Types transformer. */
private JdbcTypesTransformer transformer = JdbcTypesDefaultTransformer.INSTANCE;
/** Types that store could process. */
private JdbcType[] types;
/** Data source. */
private transient DataSource dataSrc;
/** Data source factory. */
private Factory<DataSource> dataSrcFactory;
/** Flag indicating that table and field names should be escaped in all SQL queries created by JDBC POJO store. */
private boolean sqlEscapeAll;
/** Application context. */
@SpringApplicationContextResource
private transient Object appCtx;
/** {@inheritDoc} */
@Override public CacheJdbcPojoStore<K, V> create() {
CacheJdbcPojoStore<K, V> store = new CacheJdbcPojoStore<>();
store.setBatchSize(batchSize);
store.setDialect(dialect);
store.setMaximumPoolSize(maxPoolSize);
store.setMaximumWriteAttempts(maxWrtAttempts);
store.setParallelLoadCacheMinimumThreshold(parallelLoadCacheMinThreshold);
store.setTypes(types);
store.setHasher(hasher);
store.setTransformer(transformer);
store.setSqlEscapeAll(sqlEscapeAll);
if (dataSrc != null)
store.setDataSource(dataSrc);
else if (dataSrcBean != null) {
if (appCtx == null)
throw new IgniteException("Spring application context resource is not injected.");
IgniteSpringHelper spring;
try {
spring = IgniteComponentType.SPRING.create(false);
DataSource data = spring.loadBeanFromAppContext(appCtx, dataSrcBean);
store.setDataSource(data);
}
catch (Exception e) {
throw new IgniteException("Failed to load bean in application context [beanName=" + dataSrcBean +
", igniteConfig=" + appCtx + ']', e);
}
}
else if (dataSrcFactory != null)
store.setDataSource(dataSrcFactory.create());
return store;
}
/**
* Sets data source. Data source should be fully configured and ready-to-use.
*
* @param dataSrc Data source.
* @return {@code This} for chaining.
* @see CacheJdbcPojoStore#setDataSource(DataSource)
*/
@Deprecated
public CacheJdbcPojoStoreFactory<K, V> setDataSource(DataSource dataSrc) {
this.dataSrc = dataSrc;
return this;
}
/**
* Get maximum batch size for delete and delete operations.
*
* @return Maximum batch size.
*/
public int getBatchSize() {
return batchSize;
}
/**
* Set maximum batch size for write and delete operations.
*
* @param batchSize Maximum batch size.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setBatchSize(int batchSize) {
this.batchSize = batchSize;
return this;
}
/**
* Gets name of the data source bean.
*
* @return Data source bean name.
*/
public String getDataSourceBean() {
return dataSrcBean;
}
/**
* Sets name of the data source bean.
*
* @param dataSrcBean Data source bean name.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setDataSourceBean(String dataSrcBean) {
this.dataSrcBean = dataSrcBean;
return this;
}
/**
* Get database dialect.
*
* @return Database dialect.
*/
public JdbcDialect getDialect() {
return dialect;
}
/**
* Set database dialect.
*
* @param dialect Database dialect.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setDialect(JdbcDialect dialect) {
this.dialect = dialect;
return this;
}
/**
* Get maximum workers thread count. These threads are responsible for queries execution.
*
* @return Maximum workers thread count.
*/
public int getMaximumPoolSize() {
return maxPoolSize;
}
/**
* Set Maximum workers thread count. These threads are responsible for queries execution.
*
* @param maxPoolSize Max workers thread count.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setMaximumPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
return this;
}
/**
* Gets maximum number of write attempts in case of database error.
*
* @return Maximum number of write attempts.
*/
public int getMaximumWriteAttempts() {
return maxWrtAttempts;
}
/**
* Sets maximum number of write attempts in case of database error.
*
* @param maxWrtAttempts Number of write attempts.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setMaximumWriteAttempts(int maxWrtAttempts) {
this.maxWrtAttempts = maxWrtAttempts;
return this;
}
/**
* Parallel load cache minimum row count threshold.
*
* @return If {@code 0} then load sequentially.
*/
public int getParallelLoadCacheMinimumThreshold() {
return parallelLoadCacheMinThreshold;
}
/**
* Parallel load cache minimum row count threshold.
*
* @param parallelLoadCacheMinThreshold Minimum row count threshold. If {@code 0} then load sequentially.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setParallelLoadCacheMinimumThreshold(int parallelLoadCacheMinThreshold) {
this.parallelLoadCacheMinThreshold = parallelLoadCacheMinThreshold;
return this;
}
/**
* Gets types known by store.
*
* @return Types known by store.
*/
public JdbcType[] getTypes() {
return types;
}
/**
* Sets store configurations.
*
* @param types Store should process.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setTypes(JdbcType... types) {
this.types = types;
return this;
}
/**
* Gets hash code calculator.
*
* @return Hash code calculator.
*/
public JdbcTypeHasher getHasher() {
return hasher;
}
/**
* Sets hash code calculator.
*
* @param hasher Hash code calculator.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setHasher(JdbcTypeHasher hasher) {
this.hasher = hasher;
return this;
}
/**
* Gets types transformer.
*
* @return Types transformer.
*/
public JdbcTypesTransformer getTransformer() {
return transformer;
}
/**
* Sets types transformer.
*
* @param transformer Types transformer.
* @return {@code This} for chaining.
*/
public CacheJdbcPojoStoreFactory setTransformer(JdbcTypesTransformer transformer) {
this.transformer = transformer;
return this;
}
/**
* Gets factory for underlying datasource.
*
* @return Cache store factory.
*/
@SuppressWarnings("unchecked")
public Factory<DataSource> getDataSourceFactory() {
return dataSrcFactory;
}
/**
* Sets factory for underlying datasource.
* @param dataSrcFactory Datasource factory.
* @return {@code this} for chaining.
*/
@SuppressWarnings("unchecked")
public CacheJdbcPojoStoreFactory<K, V> setDataSourceFactory(Factory<DataSource> dataSrcFactory) {
this.dataSrcFactory = dataSrcFactory;
return this;
}
/**
* If {@code true} all the SQL table and field names will be escaped with double quotes like
* ({@code "tableName"."fieldsName"}). This enforces case sensitivity for field names and
* also allows having special characters in table and field names.
*
* @return Flag value.
*/
public boolean isSqlEscapeAll() {
return sqlEscapeAll;
}
/**
* If {@code true} all the SQL table and field names will be escaped with double quotes like
* ({@code "tableName"."fieldsName"}). This enforces case sensitivity for field names and
* also allows having special characters in table and field names.
*
* @param sqlEscapeAll Flag value.
* @return {@code this} for chaining.
*/
public CacheJdbcPojoStoreFactory<K, V> setSqlEscapeAll(boolean sqlEscapeAll) {
this.sqlEscapeAll = sqlEscapeAll;
return this;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(CacheJdbcPojoStoreFactory.class, this);
}
}