blob: c52d4bc4c2ba2eeadb2fda5662db2631b6b64704 [file] [log] [blame]
/*
* 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.hibernate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.Ignition;
import org.apache.ignite.configuration.TransactionConfiguration;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
import org.apache.ignite.internal.util.typedef.G;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
/**
* Access strategy factory.
*/
public class HibernateAccessStrategyFactory {
/** */
private final HibernateKeyTransformer keyTransformer;
/** */
private final HibernateExceptionConverter eConverter;
/**
* Hibernate L2 cache grid name property name.
*
* @deprecated Use {@link #IGNITE_INSTANCE_NAME_PROPERTY}.
* If {@link #IGNITE_INSTANCE_NAME_PROPERTY} is specified it takes precedence.
*/
@Deprecated
public static final String GRID_NAME_PROPERTY = "org.apache.ignite.hibernate.grid_name";
/** Hibernate L2 cache Ignite instance name property name. */
public static final String IGNITE_INSTANCE_NAME_PROPERTY = "org.apache.ignite.hibernate.ignite_instance_name";
/** Property prefix used to specify region name to cache name mapping. */
public static final String REGION_CACHE_PROPERTY = "org.apache.ignite.hibernate.region_cache.";
/** */
public static final String DFLT_ACCESS_TYPE_PROPERTY = "org.apache.ignite.hibernate.default_access_type";
/** */
public static final String GRID_CONFIG_PROPERTY = "org.apache.ignite.hibernate.grid_config";
/** Disable atomicity check when caches are created lazily. */
public static final String VERIFY_ATOMICITY = "org.apache.ignite.hibernate.verify_atomicity";
/** When set, all cache names in ignite will be fetched using the specified prefix. */
public static final String CACHE_PREFIX = "org.apache.ignite.hibernate.cache_prefix";
/** Grid providing caches. */
private Ignite ignite;
/** Region name to cache name (without prefix) mapping. */
private final Map<String, String> regionCaches = new HashMap<>();
/** */
private final ThreadLocal threadLoc = new ThreadLocal();
/** */
private final ConcurrentHashMap<String, ThreadLocal> threadLocMap = new ConcurrentHashMap<>();
/** */
private String cachePrefix;
/** */
private boolean verifyAtomicity = true;
/**
* @param keyTransformer Key transformer.
* @param eConverter Exception converter.
*/
HibernateAccessStrategyFactory(HibernateKeyTransformer keyTransformer, HibernateExceptionConverter eConverter) {
this.keyTransformer = keyTransformer;
this.eConverter = eConverter;
}
/**
* @param cfgValues {@link Map} of config values.
*/
public void start(Map<Object, Object> cfgValues) {
cachePrefix = cfgValues.getOrDefault(CACHE_PREFIX, "").toString();
verifyAtomicity = Boolean.valueOf(cfgValues.getOrDefault(VERIFY_ATOMICITY, verifyAtomicity).toString());
Object gridCfg = cfgValues.get(GRID_CONFIG_PROPERTY);
Object igniteInstanceName = cfgValues.get(IGNITE_INSTANCE_NAME_PROPERTY);
if (gridCfg != null) {
try {
ignite = G.start(gridCfg.toString());
}
catch (IgniteException e) {
throw eConverter.convert(e);
}
}
else
ignite = Ignition.ignite(igniteInstanceName == null ? null : igniteInstanceName.toString());
for (Map.Entry entry : cfgValues.entrySet()) {
String key = entry.getKey().toString();
if (key.startsWith(REGION_CACHE_PROPERTY)) {
String regionName = key.substring(REGION_CACHE_PROPERTY.length());
String cacheName = entry.getValue().toString();
if (((IgniteKernal) ignite).getCache(cachePrefix + cacheName) == null) {
throw new IllegalArgumentException("Cache '" + cacheName + "' specified for region '" + regionName + "' " +
"is not configured.");
}
regionCaches.put(regionName, cacheName);
}
}
IgniteLogger log = ignite.log().getLogger(getClass());
if (log.isDebugEnabled())
log.debug("HibernateRegionFactory started [igniteInstanceName=" + igniteInstanceName + ']');
}
/**
* @return Ignite node.
*/
public Ignite node() {
return ignite;
}
/**
* @param regionName L2 cache region name.
* @return Cache for given region.
*/
HibernateCacheProxy regionCache(String regionName) {
String cacheName = regionCaches.get(regionName);
if (cacheName == null)
cacheName = regionName;
cacheName = cachePrefix + cacheName;
Supplier<IgniteInternalCache<Object, Object>> lazyCache = new LazyCacheSupplier(cacheName, regionName);
return new HibernateCacheProxy(cacheName, lazyCache, keyTransformer);
}
/** */
private class LazyCacheSupplier implements Supplier<IgniteInternalCache<Object, Object>> {
/** */
private final AtomicReference<IgniteInternalCache<Object, Object>> reference = new AtomicReference<>();
/** */
private final String cacheName;
/** */
private final String regionName;
/** */
private LazyCacheSupplier(String cacheName, String regionName) {
this.cacheName = cacheName;
this.regionName = regionName;
}
/** {@inheritDoc} */
@Override public IgniteInternalCache<Object, Object> get() {
IgniteInternalCache<Object, Object> cache = reference.get();
if (cache == null) {
cache = ((IgniteKernal)ignite).getCache(cacheName);
if (cache == null)
throw new IllegalArgumentException("Cache '" + cacheName + "' for region '" + regionName + "' is not configured.");
reference.compareAndSet(null, cache);
}
return cache;
}
}
/**
* @param cache Cache.
* @return Access strategy implementation.
*/
HibernateAccessStrategyAdapter createReadOnlyStrategy(HibernateCacheProxy cache) {
return new HibernateReadOnlyAccessStrategy(ignite, cache, eConverter);
}
/**
* @param cache Cache.
* @return Access strategy implementation.
*/
HibernateAccessStrategyAdapter createNonStrictReadWriteStrategy(HibernateCacheProxy cache) {
ThreadLocal threadLoc = threadLocMap.get(cache.name());
if (threadLoc == null) {
ThreadLocal old = threadLocMap.putIfAbsent(cache.name(), threadLoc = new ThreadLocal());
if (old != null)
threadLoc = old;
}
return new HibernateNonStrictAccessStrategy(ignite, cache, threadLoc, eConverter);
}
/**
* @param cache Cache.
* @return Access strategy implementation.
*/
HibernateAccessStrategyAdapter createReadWriteStrategy(HibernateCacheProxy cache) {
if (verifyAtomicity) {
if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) {
throw new IllegalArgumentException("Hibernate READ-WRITE access strategy must have Ignite cache with " +
"'TRANSACTIONAL' atomicity mode: " + cache.name());
}
}
return new HibernateReadWriteAccessStrategy(ignite, cache, threadLoc, eConverter);
}
/**
* @param cache Cache.
* @return Access strategy implementation.
*/
HibernateAccessStrategyAdapter createTransactionalStrategy(HibernateCacheProxy cache) {
if (verifyAtomicity) {
if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) {
throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite cache with " +
"'TRANSACTIONAL' atomicity mode: " + cache.name());
}
TransactionConfiguration txCfg = ignite.configuration().getTransactionConfiguration();
if (txCfg == null ||
(txCfg.getTxManagerFactory() == null
&& txCfg.getTxManagerLookupClassName() == null
&& cache.configuration().getTransactionManagerLookupClassName() == null)) {
throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite with " +
"Factory<TransactionManager> configured (see IgniteConfiguration." +
"getTransactionConfiguration().setTxManagerFactory()): " + cache.name());
}
}
return new HibernateTransactionalAccessStrategy(ignite, cache, eConverter);
}
}