All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.data.gemfire.GemfireTemplate Maven / Gradle / Ivy

There is a newer version: 2.3.9.RELEASE
Show newest version
/*
 * Copyright 2010-2013 the original author or authors.
 *
 * Licensed 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.springframework.data.gemfire;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.geode.GemFireCheckedException;
import org.apache.geode.GemFireException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.query.IndexInvalidException;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.internal.cache.LocalRegion;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Helper class that simplifies GemFire data access code and converts {@link GemFireCheckedException} and
 * {@link GemFireException} into Spring {@link DataAccessException}, following the org.springframework.dao
 * exception hierarchy.
 *
 * The central method is execute, supporting GemFire access code implementing the GemfireCallback interface.
 * It provides dedicated handling such that neither the GemfireCallback implementation nor the calling code needs to
 * explicitly care about handling {@link Region} life-cycle exceptions.
 * Typically used to implement data access or business logic services that use GemFire within their implementation but
 * are GemFire-agnostic in their interface. The latter or code calling the latter only have to deal with business
 * objects, query objects, and org.springframework.dao exceptions.
 *
 * @author Costin Leau
 * @author John Blum
 * @see java.util.Map
 * @see org.springframework.data.gemfire.GemfireAccessor
 * @see org.springframework.data.gemfire.GemfireOperations
 * @see org.apache.geode.cache.Region
 * @see org.apache.geode.cache.query.Query
 * @see org.apache.geode.cache.query.QueryService
 * @see org.apache.geode.cache.query.SelectResults
 */
@SuppressWarnings("unused")
public class GemfireTemplate extends GemfireAccessor implements GemfireOperations {

	private boolean exposeNativeRegion = false;

	private Region regionProxy;

	public GemfireTemplate() { }

	public  GemfireTemplate(Region region) {
		setRegion(region);
		afterPropertiesSet();
	}

	@Override
	public void afterPropertiesSet() {
		super.afterPropertiesSet();
		regionProxy = createRegionProxy(getRegion());
	}

	/**
	 * Sets whether to expose the native Gemfire Region to GemfireCallback code. Default is "false": a Region proxy
	 * will be returned, suppressing close calls.
	 * 

As there is often a need to cast to a interface, the exposed proxy implements all interfaces * implemented by the original {@link Region}. If this is not sufficient, turn this flag to "true". * * @param exposeNativeRegion a boolean value to indicate whether the native GemFire Cache Region should be exposed * to the GemfireCallback. * @see org.springframework.data.gemfire.GemfireCallback */ public void setExposeNativeRegion(boolean exposeNativeRegion) { this.exposeNativeRegion = exposeNativeRegion; } /** * Returns whether to expose the native GemFire Cache Region or a Region proxy to the GemfireCallback code. * * @return a boolean value indicating whether the native GemFire Cache Region or Region proxy is exposed * to the GemfireCallback code. */ public boolean isExposeNativeRegion() { return this.exposeNativeRegion; } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#containsKey(java.lang.Object) */ @Override public boolean containsKey(Object key) { return getRegion().containsKey(key); } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#containsKeyOnServer(java.lang.Object) */ @Override public boolean containsKeyOnServer(Object key) { return getRegion().containsKeyOnServer(key); } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#containsValue(java.lang.Object) */ @Override public boolean containsValue(Object value) { return getRegion().containsValue(value); } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#containsValueForKey(java.lang.Object) */ @Override public boolean containsValueForKey(Object key) { return getRegion().containsValueForKey(key); } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#create(K, V) */ @Override public void create(K key, V value) { try { getRegion().create(key, value); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#get(K) */ @Override public V get(K key) { try { return this.getRegion().get(key); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#getAll(java.util.Collection) */ @Override public Map getAll(Collection keys) { try { return this.getRegion().getAll(keys); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#put(K, V) */ @Override public V put(K key, V value) { try { return this.getRegion().put(key, value); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#putAll(java.util.Map) */ @Override public void putAll(Map map) { try { this.getRegion().putAll(map); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#putIfAbsent(K, V) */ @Override public V putIfAbsent(K key, V value) { try { return this.getRegion().putIfAbsent(key, value); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#remove(K) */ @Override public V remove(K key) { try { return this.getRegion().remove(key); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V) */ @Override public V replace(K key, V value) { try { return this.getRegion().replace(key, value); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#replace(K, V, V) */ @Override public boolean replace(K key, V oldValue, V newValue) { try { return this.getRegion().replace(key, oldValue, newValue); } catch (GemFireException e) { throw convertGemFireAccessException(e); } } /* * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#query(java.lang.String) */ @Override public SelectResults query(String query) { try { return this.getRegion().query(query); } catch (IndexInvalidException e) { throw convertGemFireQueryException(e); } catch (QueryInvalidException e) { throw convertGemFireQueryException(e); } catch (GemFireCheckedException e) { throw convertGemFireAccessException(e); } catch (GemFireException e) { throw convertGemFireAccessException(e); } catch (RuntimeException ex) { // test for CqInvalidException (removed in 6.5) if (GemfireCacheUtils.isCqInvalidException(ex)) { throw GemfireCacheUtils.convertCqInvalidException(ex); } // callback code threw application exception throw ex; } } /* * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#find(java.lang.String, java.lang.Object) */ @Override @SuppressWarnings("unchecked") public SelectResults find(String queryString, Object... params) throws InvalidDataAccessApiUsageException { try { QueryService queryService = resolveQueryService(getRegion()); Query query = queryService.newQuery(queryString); Object result = query.execute(params); if (result instanceof SelectResults) { return (SelectResults) result; } else { throw new InvalidDataAccessApiUsageException(String.format( "The result from executing query [%1$s] was not an instance of SelectResults [%2$s]", queryString, result)); } } catch (IndexInvalidException | QueryInvalidException e) { throw convertGemFireQueryException(e); } catch (GemFireCheckedException e) { throw convertGemFireAccessException(e); } catch (GemFireException e) { throw convertGemFireAccessException(e); } catch (RuntimeException e) { // test for CqInvalidException (removed in 6.5) if (GemfireCacheUtils.isCqInvalidException(e)) { throw GemfireCacheUtils.convertCqInvalidException(e); } // callback code threw application exception throw e; } } /* * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#findUnique(java.lang.String, java.lang.Object) */ @Override @SuppressWarnings("unchecked") public T findUnique(String queryString, Object... params) throws InvalidDataAccessApiUsageException { try { QueryService queryService = resolveQueryService(getRegion()); Query query = queryService.newQuery(queryString); Object result = query.execute(params); if (result instanceof SelectResults) { SelectResults selectResults = (SelectResults) result; List results = selectResults.asList(); if (results.size() == 1) { result = results.get(0); } else { throw new InvalidDataAccessApiUsageException(String.format( "The result returned from query [%1$s]) was not unique [%2$s]", queryString, result)); } } return (T) result; } catch (IndexInvalidException ex) { throw convertGemFireQueryException(ex); } catch (QueryInvalidException ex) { throw convertGemFireQueryException(ex); } catch (GemFireCheckedException e) { throw convertGemFireAccessException(e); } catch (GemFireException e) { throw convertGemFireAccessException(e); } catch (RuntimeException ex) { // test for CqInvalidException (removed in 6.5) if (GemfireCacheUtils.isCqInvalidException(ex)) { throw GemfireCacheUtils.convertCqInvalidException(ex); } // callback code threw application exception throw ex; } } /** * Returns the {@link QueryService} used by this template in its query/finder methods. * * @param region {@link Region} used to acquire the {@link QueryService}. * @return the {@link QueryService} that will perform the query. * @see org.apache.geode.cache.Region * @see org.apache.geode.cache.Region#getRegionService() * @see org.apache.geode.cache.RegionService#getQueryService() * @see org.apache.geode.cache.client.ClientCache#getLocalQueryService() */ protected QueryService resolveQueryService(Region region) { return (region.getRegionService() instanceof ClientCache ? resolveClientQueryService(region) : queryServiceFrom(region)); } /* (non-Javadoc) */ QueryService resolveClientQueryService(Region region) { ClientCache clientCache = (ClientCache) region.getRegionService(); return (requiresLocalQueryService(region) ? clientCache.getLocalQueryService() : (requiresPooledQueryService(region) ? clientCache.getQueryService(poolNameFrom(region)) : queryServiceFrom(region))); } /* (non-Javadoc) */ boolean requiresLocalQueryService(Region region) { return (Scope.LOCAL.equals(region.getAttributes().getScope()) && isLocalWithNoServerProxy(region)); } /* (non-Javadoc) */ boolean isLocalWithNoServerProxy(Region region) { return (region instanceof LocalRegion && !((LocalRegion) region).hasServerProxy()); } boolean requiresPooledQueryService(Region region) { return StringUtils.hasText(poolNameFrom(region)); } /* (non-Javadoc) */ QueryService queryServiceFrom(Region region) { return region.getRegionService().getQueryService(); } /* (non-Javadoc) */ String poolNameFrom(Region region) { return region.getAttributes().getPoolName(); } /* * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback) */ @Override public T execute(GemfireCallback action) throws DataAccessException { return execute(action, isExposeNativeRegion()); } /* * (non-Javadoc) * @see org.springframework.data.gemfire.GemfireOperations#execute(org.springframework.data.gemfire.GemfireCallback, boolean) */ @Override public T execute(GemfireCallback action, boolean exposeNativeRegion) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); try { Region regionArgument = (exposeNativeRegion ? getRegion() : regionProxy); return action.doInGemfire(regionArgument); } catch (IndexInvalidException ex) { throw convertGemFireQueryException(ex); } catch (QueryInvalidException ex) { throw convertGemFireQueryException(ex); } catch (GemFireCheckedException ex) { throw convertGemFireAccessException(ex); } catch (GemFireException ex) { throw convertGemFireAccessException(ex); } catch (RuntimeException ex) { // test for CqInvalidException (removed in 6.5) if (GemfireCacheUtils.isCqInvalidException(ex)) { throw GemfireCacheUtils.convertCqInvalidException(ex); } // callback code threw application exception throw ex; } } /** * Create a close-suppressing proxy for the given GemFire Cache {@link Region}. * Called by the execute method. * * @param the Region key class type. * @param the Region value class type. * @param region the GemFire Cache Region to create a proxy for. * @return the Region proxy implementing all interfaces implemented by the passed-in Region object. * @see org.apache.geode.cache.Region#close() * @see #execute(GemfireCallback, boolean) */ @SuppressWarnings("unchecked") protected Region createRegionProxy(Region region) { Class regionType = region.getClass(); return (Region) Proxy.newProxyInstance(regionType.getClassLoader(), ClassUtils.getAllInterfacesForClass(regionType, getClass().getClassLoader()), new RegionCloseSuppressingInvocationHandler(region)); } /** * InvocationHandler that suppresses close calls on GemFire Cache Regions. * * @see org.apache.geode.cache.Region#close() * @see java.lang.reflect.InvocationHandler */ private static class RegionCloseSuppressingInvocationHandler implements InvocationHandler { private final Region target; public RegionCloseSuppressingInvocationHandler(final Region target) { Assert.notNull(target, "The Region to target must not be null."); this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("equals")) { // only consider equal when proxies are identical return (proxy == args[0]); } else if (method.getName().equals("hashCode")) { // use hashCode of Region proxy return System.identityHashCode(proxy); } else if (method.getName().equals("close")) { // suppress Region.close() method call return null; } else { try { return method.invoke(this.target, args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy