/*
* 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.Properties;
import java.util.concurrent.ConcurrentHashMap;
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";
/** Default cache property name. */
public static final String DFLT_CACHE_NAME_PROPERTY = "org.apache.ignite.hibernate.default_cache";
/** 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";
/** Grid providing caches. */
private Ignite ignite;
/** Default cache. */
private HibernateCacheProxy dfltCache;
/** Region name to cache name mapping. */
private final Map<String, String> regionCaches = new HashMap<>();
/** */
private final ThreadLocal threadLoc = new ThreadLocal();
/** */
private final ConcurrentHashMap<String, ThreadLocal> threadLocMap = new ConcurrentHashMap<>();
/**
* @param keyTransformer Key transformer.
* @param eConverter Exception converter.
*/
HibernateAccessStrategyFactory(HibernateKeyTransformer keyTransformer, HibernateExceptionConverter eConverter) {
this.keyTransformer = keyTransformer;
this.eConverter = eConverter;
}
/**
* @param props Properties.
*/
public void start(Properties props) {
String gridCfg = props.getProperty(GRID_CONFIG_PROPERTY);
String igniteInstanceName = props.getProperty(IGNITE_INSTANCE_NAME_PROPERTY);
if (igniteInstanceName == null)
igniteInstanceName = props.getProperty(GRID_NAME_PROPERTY);
if (gridCfg != null) {
try {
ignite = G.start(gridCfg);
}
catch (IgniteException e) {
throw eConverter.convert(e);
}
}
else
ignite = Ignition.ignite(igniteInstanceName);
for (Map.Entry<Object, Object> prop : props.entrySet()) {
String key = prop.getKey().toString();
if (key.startsWith(REGION_CACHE_PROPERTY)) {
String regionName = key.substring(REGION_CACHE_PROPERTY.length());
String cacheName = prop.getValue().toString();
if (((IgniteKernal)ignite).getCache(cacheName) == null)
throw new IllegalArgumentException("Cache '" + cacheName + "' specified for region '" + regionName + "' " +
"is not configured.");
regionCaches.put(regionName, cacheName);
}
}
String dfltCacheName = props.getProperty(DFLT_CACHE_NAME_PROPERTY);
if (dfltCacheName != null) {
IgniteInternalCache<Object, Object> dfltCache = ((IgniteKernal)ignite).getCache(dfltCacheName);
if (dfltCache == null)
throw new IllegalArgumentException("Cache specified as default is not configured: " + dfltCacheName);
this.dfltCache = new HibernateCacheProxy(dfltCache, keyTransformer);
}
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) {
if (dfltCache != null)
return dfltCache;
cacheName = regionName;
}
IgniteInternalCache<Object, Object> cache = ((IgniteKernal)ignite).getCache(cacheName);
if (cache == null)
throw new IllegalArgumentException("Cache '" + cacheName + "' for region '" + regionName + "' is not configured.");
return new HibernateCacheProxy(cache, keyTransformer);
}
/**
* @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 (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 (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);
}
}