diff --git a/gradle.properties b/gradle.properties index dad39b34..30eafcd4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ log4jVersion = 1.2.16 slf4jVersion = 1.6.4 # Common libraries -springVersion = 3.1.2.RELEASE +springVersion = 3.2.0.RC1 springDataCommonsVersion = 1.4.0.RELEASE gemfireVersion = 7.0 diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 04002783..d772dafa 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.io.Resource; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; @@ -75,12 +76,14 @@ import com.gemstone.gemfire.pdx.PdxSerializer; * @author David Turanski */ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, DisposableBean, - InitializingBean, FactoryBean, PersistenceExceptionTranslator { + InitializingBean, FactoryBean, PersistenceExceptionTranslator { /** * Inner class to avoid a hard dependency on the GemFire 6.6 API. * * @author Costin Leau */ + + private class PdxOptions implements Runnable { private final CacheFactory factory; @@ -277,10 +280,11 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl factoryLocator.afterPropertiesSet(); } Properties cfgProps = mergeProperties(); - + // use the bean class loader to load Declarable classes Thread th = Thread.currentThread(); ClassLoader oldTCCL = th.getContextClassLoader(); + try { th.setContextClassLoader(beanClassLoader); @@ -329,6 +333,7 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl log.debug("Initialized cache from " + cacheXml); } } + setHeapPercentages(); registerTransactionListeners(); registerTransactionWriter(); @@ -680,4 +685,7 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl public void setJndiDataSources(List jndiDataSources) { this.jndiDataSources = jndiDataSources; } + + + } diff --git a/src/main/java/org/springframework/data/gemfire/GemfireBeanPostProcessor.java b/src/main/java/org/springframework/data/gemfire/GemfireBeanPostProcessor.java new file mode 100644 index 00000000..410894ed --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/GemfireBeanPostProcessor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2012 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 org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +/** + * + * Work around to ensure dependent disk stores are created before gateway senders + * + * @author David Turanski + * + */ +public class GemfireBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { + + private DefaultListableBeanFactory beanFactory; + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String) + */ + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory) + */ + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = (DefaultListableBeanFactory)beanFactory; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/GemfireCallback.java b/src/main/java/org/springframework/data/gemfire/GemfireCallback.java index a8c1a3d7..af21ebbd 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireCallback.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireCallback.java @@ -40,6 +40,5 @@ public interface GemfireCallback { * @param region GemFire Region * @return a result object, or null if none */ - @SuppressWarnings("unchecked") - T doInGemfire(Region region) throws GemFireCheckedException, GemFireException; + T doInGemfire(Region region) throws GemFireCheckedException, GemFireException; } diff --git a/src/main/java/org/springframework/data/gemfire/GemfireCancellationException.java b/src/main/java/org/springframework/data/gemfire/GemfireCancellationException.java index 66975a08..5861a729 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireCancellationException.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireCancellationException.java @@ -25,6 +25,7 @@ import com.gemstone.gemfire.CancelException; * * @author Costin Leau */ +@SuppressWarnings("serial") public class GemfireCancellationException extends InvalidDataAccessResourceUsageException { public GemfireCancellationException(CancelException ex) { diff --git a/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java b/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java index 50a07a84..5b329b4c 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireIndexException.java @@ -29,6 +29,7 @@ import com.gemstone.gemfire.cache.query.IndexNameConflictException; * * @author Costin Leau */ +@SuppressWarnings("serial") public class GemfireIndexException extends DataIntegrityViolationException { public GemfireIndexException(IndexCreationException ex) { diff --git a/src/main/java/org/springframework/data/gemfire/GemfireQueryException.java b/src/main/java/org/springframework/data/gemfire/GemfireQueryException.java index b0a1c483..86f3da85 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireQueryException.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireQueryException.java @@ -28,6 +28,7 @@ import com.gemstone.gemfire.cache.query.QueryInvalidException; * * @author Costin Leau */ +@SuppressWarnings("serial") public class GemfireQueryException extends InvalidDataAccessResourceUsageException { public GemfireQueryException(String message, QueryException ex) { diff --git a/src/main/java/org/springframework/data/gemfire/GemfireSystemException.java b/src/main/java/org/springframework/data/gemfire/GemfireSystemException.java index 3611db75..64569510 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireSystemException.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireSystemException.java @@ -26,6 +26,7 @@ import com.gemstone.gemfire.GemFireException; * * @author Costin Leau */ +@SuppressWarnings("serial") public class GemfireSystemException extends UncategorizedDataAccessException { public GemfireSystemException(GemFireCheckedException ex) { diff --git a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java index 7f9b0e71..22f9564e 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireTemplate.java @@ -98,8 +98,7 @@ public class GemfireTemplate extends GemfireAccessor { public boolean containsKey(final Object key) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { + public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.containsKey(key); } }); @@ -107,8 +106,7 @@ public class GemfireTemplate extends GemfireAccessor { public boolean containsKeyOnServer(final Object key) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { + public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.containsKeyOnServer(key); } }); @@ -116,8 +114,7 @@ public class GemfireTemplate extends GemfireAccessor { public boolean containsValue(final Object value) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { + public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.containsValue(value); } }); @@ -125,8 +122,7 @@ public class GemfireTemplate extends GemfireAccessor { public boolean containsValueForKey(final Object key) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") - public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { + public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.containsValueForKey(key); } }); @@ -134,7 +130,7 @@ public class GemfireTemplate extends GemfireAccessor { public void create(final K key, final V value) { execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public Object doInGemfire(Region region) throws GemFireCheckedException, GemFireException { region.create(key, value); return null; @@ -144,7 +140,7 @@ public class GemfireTemplate extends GemfireAccessor { public V get(final K key) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (V) region.get(key); } @@ -153,7 +149,7 @@ public class GemfireTemplate extends GemfireAccessor { public V put(final K key, final V value) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (V) region.put(key, value); } @@ -162,7 +158,7 @@ public class GemfireTemplate extends GemfireAccessor { public V putIfAbsent(final K key, final V value) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (V) region.putIfAbsent(key, value); } @@ -171,7 +167,7 @@ public class GemfireTemplate extends GemfireAccessor { public V remove(final K key) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (V) region.remove(key); } @@ -180,7 +176,7 @@ public class GemfireTemplate extends GemfireAccessor { public V replace(final K key, final V value) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public V doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (V) region.replace(key, value); } @@ -189,7 +185,7 @@ public class GemfireTemplate extends GemfireAccessor { public boolean replace(final K key, final V oldValue, final V newValue) { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public Boolean doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.replace(key, oldValue, newValue); } @@ -198,7 +194,7 @@ public class GemfireTemplate extends GemfireAccessor { public Map getAll(final Collection keys) { return execute(new GemfireCallback>() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public Map doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return (Map) region.getAll(keys); } @@ -207,7 +203,7 @@ public class GemfireTemplate extends GemfireAccessor { public void putAll(final Map map) { execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public Object doInGemfire(Region region) throws GemFireCheckedException, GemFireException { region.putAll(map); return null; @@ -228,7 +224,7 @@ public class GemfireTemplate extends GemfireAccessor { */ public SelectResults query(final String query) { return execute(new GemfireCallback>() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public SelectResults doInGemfire(Region region) throws GemFireCheckedException, GemFireException { return region.query(query); } @@ -255,7 +251,7 @@ public class GemfireTemplate extends GemfireAccessor { public SelectResults find(final String query, final Object... params) throws InvalidDataAccessApiUsageException { return execute(new GemfireCallback>() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public SelectResults doInGemfire(Region region) throws GemFireCheckedException, GemFireException { QueryService queryService = lookupQueryService(region); Query q = queryService.newQuery(query); @@ -287,7 +283,7 @@ public class GemfireTemplate extends GemfireAccessor { */ public T findUnique(final String query, final Object... params) throws InvalidDataAccessApiUsageException { return execute(new GemfireCallback() { - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public T doInGemfire(Region region) throws GemFireCheckedException, GemFireException { QueryService queryService = lookupQueryService(region); Query q = queryService.newQuery(query); diff --git a/src/main/java/org/springframework/data/gemfire/GemfireTransactionCommitException.java b/src/main/java/org/springframework/data/gemfire/GemfireTransactionCommitException.java index ddc5a470..071eb518 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireTransactionCommitException.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireTransactionCommitException.java @@ -23,6 +23,7 @@ import org.springframework.transaction.TransactionException; * * @author Costin Leau */ +@SuppressWarnings("serial") public class GemfireTransactionCommitException extends TransactionException { public GemfireTransactionCommitException(String message, Throwable cause) { diff --git a/src/main/java/org/springframework/data/gemfire/GemfireTransactionManager.java b/src/main/java/org/springframework/data/gemfire/GemfireTransactionManager.java index d6207184..f12fcdab 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireTransactionManager.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireTransactionManager.java @@ -64,6 +64,7 @@ import com.gemstone.gemfire.cache.Region; */ // TODO add lenient behavior if a transaction is already started on the current // thread (what should happen then) +@SuppressWarnings("serial") public class GemfireTransactionManager extends AbstractPlatformTransactionManager implements InitializingBean, ResourceTransactionManager { @@ -218,7 +219,7 @@ public class GemfireTransactionManager extends AbstractPlatformTransactionManage */ public void setRegion(Region region) { Assert.notNull(region, "non-null arguments are required"); - this.cache = region.getCache(); + this.cache = (Cache)region.getRegionService(); } /** @@ -271,6 +272,7 @@ public class GemfireTransactionManager extends AbstractPlatformTransactionManage private boolean rollbackOnly = false; + @SuppressWarnings("unused") public boolean isRollbackOnly() { return rollbackOnly; } diff --git a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java index 4b804a68..877a64b6 100644 --- a/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/IndexFactoryBean.java @@ -28,8 +28,13 @@ import com.gemstone.gemfire.cache.RegionService; import com.gemstone.gemfire.cache.client.Pool; import com.gemstone.gemfire.cache.client.PoolManager; import com.gemstone.gemfire.cache.query.Index; +import com.gemstone.gemfire.cache.query.IndexExistsException; +import com.gemstone.gemfire.cache.query.IndexInvalidException; +import com.gemstone.gemfire.cache.query.IndexNameConflictException; import com.gemstone.gemfire.cache.query.IndexType; import com.gemstone.gemfire.cache.query.QueryService; +import com.gemstone.gemfire.cache.query.RegionNotFoundException; +import com.springsource.vfabric.licensing.log.Logger; /** * Factory bean for easy declarative creation of GemFire Indexes. @@ -71,7 +76,7 @@ public class IndexFactoryBean implements InitializingBean, BeanNameAware, Factor index = createIndex(queryService, indexName); } - private Index createIndex(QueryService queryService, String indexName) throws Exception { + private Index createIndex(QueryService queryService, String indexName) throws Exception { Collection indexes = queryService.getIndexes(); Index old = null; @@ -95,13 +100,17 @@ public class IndexFactoryBean implements InitializingBean, BeanNameAware, Factor } Index index = null; - + try { if (StringUtils.hasText(imports)) { index = queryService.createIndex(indexName, type, expression, from, imports); } else { index = queryService.createIndex(indexName, type, expression, from); } + + } catch (IndexExistsException e) { + // This is ok + } return index; } diff --git a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java index ecceee72..878f2bc8 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java @@ -21,13 +21,14 @@ import java.lang.reflect.Field; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; +import org.springframework.context.SmartLifecycle; import org.springframework.core.io.Resource; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.wan.SmartLifecycleGatewaySender; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; -import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue; import com.gemstone.gemfire.cache.AttributesFactory; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheClosedException; @@ -40,6 +41,7 @@ import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.RegionAttributes; import com.gemstone.gemfire.cache.RegionFactory; import com.gemstone.gemfire.cache.Scope; +import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue; import com.gemstone.gemfire.cache.wan.GatewaySender; /** @@ -55,7 +57,11 @@ import com.gemstone.gemfire.cache.wan.GatewaySender; * @author Costin Leau * @author David Turanski */ -public class RegionFactoryBean extends RegionLookupFactoryBean implements DisposableBean { +public class RegionFactoryBean extends RegionLookupFactoryBean implements DisposableBean, SmartLifecycle { + + private boolean autoStartup = true; + + private boolean running; protected final Log log = LogFactory.getLog(getClass()); @@ -150,13 +156,13 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple if (cacheWriter != null) { regionFactory.setCacheWriter(cacheWriter); } - + if (diskStoreName != null) { regionFactory.setDiskStoreName(diskStoreName); - Assert.isTrue(!isNotPersistent(),"it is invalid to specify a disk store if 'persistent' is set to false."); + Assert.isTrue(!isNotPersistent(), "it is invalid to specify a disk store if 'persistent' is set to false."); persistent = true; } - + resolveDataPolicy(regionFactory, persistent, dataPolicy); if (scope != null) { @@ -194,8 +200,7 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple if (dataPolicy == null) { if (isPersistent()) { regionFactory.setDataPolicy(DataPolicy.PERSISTENT_REPLICATE); - } - else { + } else { regionFactory.setDataPolicy(DataPolicy.DEFAULT); } return; @@ -238,23 +243,21 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple * @param region */ protected void postProcess(Region region) { - // do nothing + } @Override public void destroy() throws Exception { if (region != null) { if (close) { - if (!region.getCache().isClosed()) { + if (!region.getRegionService().isClosed()) { try { region.close(); - } - catch (CacheClosedException cce) { + } catch (CacheClosedException cce) { // nothing to see folks, move on. } } - } - else if (destroy) { + } else if (destroy) { region.destroyRegion(); } } @@ -414,4 +417,73 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple protected boolean isNotPersistent() { return persistent != null && !persistent; } + + /* (non-Javadoc) + * @see org.springframework.context.Lifecycle#start() + */ + @Override + public void start() { + + if (!ObjectUtils.isEmpty(gatewaySenders)) { + synchronized (gatewaySenders) { + for (Object obj : gatewaySenders) { + SmartLifecycleGatewaySender gws = (SmartLifecycleGatewaySender) obj; + if (gws.isAutoStartup() && !gws.isRunning()) { + gws.start(); + } + } + } + } + this.running = true; + } + + /* (non-Javadoc) + * @see org.springframework.context.Lifecycle#stop() + */ + @Override + public void stop() { + if (!ObjectUtils.isEmpty(gatewaySenders)) { + synchronized (gatewaySenders) { + for (Object obj : gatewaySenders) { + SmartLifecycleGatewaySender gws = (SmartLifecycleGatewaySender) obj; + gws.stop(); + } + } + } + this.running = false; + } + + /* (non-Javadoc) + * @see org.springframework.context.Lifecycle#isRunning() + */ + @Override + public boolean isRunning() { + return this.running; + } + + /* (non-Javadoc) + * @see org.springframework.context.Phased#getPhase() + */ + @Override + public int getPhase() { + return Integer.MAX_VALUE; + } + + /* (non-Javadoc) + * @see org.springframework.context.SmartLifecycle#isAutoStartup() + */ + @Override + public boolean isAutoStartup() { + return this.autoStartup; + } + + /* (non-Javadoc) + * @see org.springframework.context.SmartLifecycle#stop(java.lang.Runnable) + */ + @Override + public void stop(Runnable callback) { + stop(); + callback.run(); + } + } diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java index 86b168d0..080b85c6 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -19,6 +19,7 @@ package org.springframework.data.gemfire.client; import java.net.InetSocketAddress; import java.util.List; import java.util.Properties; +import java.util.logging.Handler; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.data.gemfire.CacheFactoryBean; @@ -26,11 +27,15 @@ import org.springframework.data.gemfire.config.GemfireConstants; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import com.gemstone.gemfire.LogWriter; import com.gemstone.gemfire.cache.GemFireCache; import com.gemstone.gemfire.cache.client.ClientCacheFactory; import com.gemstone.gemfire.cache.client.Pool; import com.gemstone.gemfire.cache.client.PoolManager; import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem; +import com.gemstone.gemfire.i18n.LogWriterI18n; +import com.gemstone.gemfire.i18n.StringId; import com.gemstone.gemfire.pdx.PdxSerializer; /** @@ -103,16 +108,15 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { if (StringUtils.hasText(poolName)) { p = PoolManager.find(poolName); } - // initialize a client-like Distributed System before initializing - // the pool + // Bind this client cache to a pool that hasn't been created yet. + + // initialize a client-like Distributed System before initializing + // the pool + if (p == null) { - Properties prop = mergeProperties(); - prop.setProperty("mcast-port", "0"); - prop.setProperty("locators", ""); - - DistributedSystem system = DistributedSystem.connect(prop); + PoolFactoryBean.connectToTemporaryDs(); } - + if (StringUtils.hasText(poolName)) { try { @@ -134,6 +138,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { p = getBeanFactory().getBean(Pool.class); this.poolName = p.getName(); } + } if (p != null) { @@ -167,7 +172,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { } List servers = p.getServers(); - if (locators != null) { + if (servers != null) { for (InetSocketAddress inet : servers) { ccf.addPoolServer(inet.getHostName(), inet.getPort()); } diff --git a/src/main/java/org/springframework/data/gemfire/client/PoolConnection.java b/src/main/java/org/springframework/data/gemfire/client/PoolConnection.java deleted file mode 100644 index 15c6e971..00000000 --- a/src/main/java/org/springframework/data/gemfire/client/PoolConnection.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010-2012 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.client; - -/** - * Simple holder class used for configuring servers or locators for GemFire pools. - * - * @see com.gemstone.gemfire.cache.client.PoolFactory - * - * @author Costin Leau - */ -public class PoolConnection { - - private String host; - private int port; - - /** - * @return the host - */ - public String getHost() { - return host; - } - - /** - * @param host the host to set - */ - public void setHost(String host) { - this.host = host; - } - - /** - * @return the port - */ - public int getPort() { - return port; - } - - /** - * @param port the port to set - */ - public void setPort(int port) { - this.port = port; - } -} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java index 1e1167ec..b62b7989 100644 --- a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.client; import java.util.Collection; +import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -34,7 +35,9 @@ import com.gemstone.gemfire.cache.GemFireCache; import com.gemstone.gemfire.cache.client.Pool; import com.gemstone.gemfire.cache.client.PoolFactory; import com.gemstone.gemfire.cache.client.PoolManager; +import com.gemstone.gemfire.distributed.DistributedSystem; import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem; +import java.net.InetSocketAddress; /** * Factory bean for easy declaration and configuration of a GemFire pool. If a @@ -63,8 +66,8 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, // pool settings private String beanName; private String name; - private Collection locators; - private Collection servers; + private Collection locators; + private Collection servers; private BeanFactory beanFactory; @@ -109,8 +112,8 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, // eagerly initialize cache (if needed) if (InternalDistributedSystem.getAnyInstance() == null) { - // no cache found, do eager initialization - beanFactory.getBean(GemFireCache.class); + // no cache found, create a temp connection + connectToTemporaryDs(); } // first check the configured pools @@ -137,15 +140,15 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, PoolFactory poolFactory = PoolManager.createFactory(); if (!CollectionUtils.isEmpty(locators)) { - for (PoolConnection connection : locators) { - poolFactory.addLocator(connection.getHost(), + for (InetSocketAddress connection : locators) { + poolFactory.addLocator(connection.getHostName(), connection.getPort()); } } if (!CollectionUtils.isEmpty(servers)) { - for (PoolConnection connection : servers) { - poolFactory.addServer(connection.getHost(), + for (InetSocketAddress connection : servers) { + poolFactory.addServer(connection.getHostName(), connection.getPort()); } } @@ -209,7 +212,7 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, * @param locators * the locators to set */ - public void setLocators(Collection locators) { + public void setLocators(Collection locators) { this.locators = locators; } @@ -217,7 +220,7 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, * @param servers * the servers to set */ - public void setServers(Collection servers) { + public void setServers(Collection servers) { this.servers = servers; } @@ -377,4 +380,16 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, public void setPrSingleHopEnabled(boolean prSingleHopEnabled) { this.prSingleHopEnabled = prSingleHopEnabled; } + + /* + * A work around to create a pool if no cache has been created yet + * initialize a client-like Distributed System before initializing + * the pool + */ + static void connectToTemporaryDs() { + Properties prop = new Properties(); + prop.setProperty("mcast-port", "0"); + prop.setProperty("locators", ""); + DistributedSystem.connect(prop); + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/config/AsyncEventQueueParser.java b/src/main/java/org/springframework/data/gemfire/config/AsyncEventQueueParser.java index ef7d697c..7a29287c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/AsyncEventQueueParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/AsyncEventQueueParser.java @@ -19,11 +19,10 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.gemfire.wan.AsyncEventQueueFactoryBean; +import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; -import com.gemstone.gemfire.internal.lang.StringUtils; - /** * @author David Turanski * @@ -41,8 +40,10 @@ public class AsyncEventQueueParser extends AbstractSingleBeanDefinitionParser { Element asyncEventListenerElement = DomUtils.getChildElementByTagName(element, "async-event-listener"); Object asyncEventListener = ParsingUtils.parseRefOrSingleNestedBeanDeclaration(parserContext, asyncEventListenerElement, builder); - String cacheName = StringUtils.isEmpty(element.getAttribute("cache-ref")) ? "gemfireCache" : element - .getAttribute("cache-ref"); + + String cacheName = !StringUtils.hasText(element.getAttribute("cache-ref")) ? GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME + : element.getAttribute("cache-ref"); + builder.addConstructorArgReference(cacheName); builder.addConstructorArgValue(asyncEventListener); ParsingUtils.setPropertyValue(element, builder, "batch-size"); @@ -50,5 +51,23 @@ public class AsyncEventQueueParser extends AbstractSingleBeanDefinitionParser { ParsingUtils.setPropertyValue(element, builder, "disk-store-ref"); ParsingUtils.setPropertyValue(element, builder, "persistent"); ParsingUtils.setPropertyValue(element, builder, "parallel"); + ParsingUtils.setPropertyValue(element, builder, NAME_ATTRIBUTE); + + if (!StringUtils.hasText(element.getAttribute(NAME_ATTRIBUTE))) { + if (element.getParentNode().getNodeName().endsWith("region")) { + Element region = (Element) element.getParentNode(); + String regionName = StringUtils.hasText(region.getAttribute("name")) ? region.getAttribute("name") + : region.getAttribute("id"); + + int i = 0; + String name = regionName + ".asyncEventQueue#" + i; + while (parserContext.getRegistry().isBeanNameInUse(name)) { + i++; + name = regionName + ".asyncEventQueue#" + i; + } + + builder.addPropertyValue("name", name); + } + } } } diff --git a/src/main/java/org/springframework/data/gemfire/config/CacheParser.java b/src/main/java/org/springframework/data/gemfire/config/CacheParser.java index e171102f..6bd6fcfa 100644 --- a/src/main/java/org/springframework/data/gemfire/config/CacheParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/CacheParser.java @@ -19,6 +19,7 @@ package org.springframework.data.gemfire.config; import java.util.List; import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; @@ -26,6 +27,7 @@ import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.GemfireBeanPostProcessor; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; @@ -52,6 +54,9 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, builder); + +// BeanDefinition gemfirePostProcessor = BeanDefinitionBuilder.genericBeanDefinition(GemfireBeanPostProcessor.class).getBeanDefinition(); +// parserContext.getRegistry().registerBeanDefinition(GemfireBeanPostProcessor.class.getName(), gemfirePostProcessor); ParsingUtils.setPropertyValue(element, builder, "cache-xml-location", "cacheXml"); ParsingUtils.setPropertyReference(element, builder, "properties-ref", "properties"); diff --git a/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java b/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java index b9339092..9718c12c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java @@ -37,7 +37,7 @@ class ClientCacheParser extends CacheParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, parserContext, builder); - ParsingUtils.setPropertyValue(element, builder, "pool-name"); + //ParsingUtils.setPropertyValue(element, builder, "pool-name","poolName",GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME); } @Override diff --git a/src/main/java/org/springframework/data/gemfire/config/GatewaySenderParser.java b/src/main/java/org/springframework/data/gemfire/config/GatewaySenderParser.java index a42392b0..e79880ac 100644 --- a/src/main/java/org/springframework/data/gemfire/config/GatewaySenderParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/GatewaySenderParser.java @@ -36,10 +36,12 @@ class GatewaySenderParser extends AbstractSimpleBeanDefinitionParser { @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - builder.setLazyInit(false); + String cacheRef = element.getAttribute("cache-ref"); + // add cache reference (fallback to default if nothing is specified) - builder.addConstructorArgReference((StringUtils.hasText(cacheRef) ? cacheRef : "gemfireCache")); + builder.addConstructorArgReference((StringUtils.hasText(cacheRef) ? cacheRef + : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)); ParsingUtils.setPropertyValue(element, builder, "alert-threshold"); ParsingUtils.setPropertyValue(element, builder, "batch-size"); ParsingUtils.setPropertyValue(element, builder, "batch-time-interval"); @@ -55,6 +57,7 @@ class GatewaySenderParser extends AbstractSimpleBeanDefinitionParser { ParsingUtils.setPropertyValue(element, builder, "socket-read-timeout"); ParsingUtils.setPropertyValue(element, builder, "persistent"); ParsingUtils.setPropertyValue(element, builder, "parallel"); + ParsingUtils.setPropertyValue(element, builder, NAME_ATTRIBUTE); Element eventFilterElement = DomUtils.getChildElementByTagName(element, "event-filter"); if (eventFilterElement != null) { @@ -63,5 +66,25 @@ class GatewaySenderParser extends AbstractSimpleBeanDefinitionParser { } ParsingUtils.parseTransportFilters(element, parserContext, builder); + + /** + * set the name for an inner bean + */ + if (!StringUtils.hasText(element.getAttribute(NAME_ATTRIBUTE))) { + if (element.getParentNode().getNodeName().endsWith("region")) { + Element region = (Element) element.getParentNode(); + String regionName = StringUtils.hasText(region.getAttribute("name")) ? region.getAttribute("name") + : region.getAttribute("id"); + + int i = 0; + String name = regionName + ".gatewaySender#" + i; + while (parserContext.getRegistry().isBeanNameInUse(name)) { + i++; + name = regionName + ".gatewaySender#" + i; + } + + builder.addPropertyValue("name", name); + } + } } } diff --git a/src/main/java/org/springframework/data/gemfire/config/PoolParser.java b/src/main/java/org/springframework/data/gemfire/config/PoolParser.java index bfa83e42..951c3ef6 100644 --- a/src/main/java/org/springframework/data/gemfire/config/PoolParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/PoolParser.java @@ -16,6 +16,7 @@ package org.springframework.data.gemfire.config; +import java.net.InetSocketAddress; import java.util.List; import org.springframework.beans.factory.BeanDefinitionStoreException; @@ -25,7 +26,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.gemfire.client.PoolConnection; import org.springframework.data.gemfire.client.PoolFactoryBean; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; @@ -35,13 +35,16 @@ import org.w3c.dom.Element; * Parser for <pool;gt; definitions. * * @author Costin Leau + * @author David Turanski */ class PoolParser extends AbstractSimpleBeanDefinitionParser { + @Override protected Class getBeanClass(Element element) { return PoolFactoryBean.class; } - + + @Override protected void postProcess(BeanDefinitionBuilder builder, Element element) { List subElements = DomUtils.getChildElements(element); ManagedList locators = new ManagedList(subElements.size()); @@ -77,9 +80,9 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser { } private BeanDefinition parseConnection(Element element) { - BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(PoolConnection.class); - ParsingUtils.setPropertyValue(element, defBuilder, "host", "host"); - ParsingUtils.setPropertyValue(element, defBuilder, "port", "port"); + BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(InetSocketAddress.class); + defBuilder.addConstructorArgValue(element.getAttribute("host")); + defBuilder.addConstructorArgValue(element.getAttribute("port")); return defBuilder.getBeanDefinition(); } diff --git a/src/main/java/org/springframework/data/gemfire/function/DefaultFunctionArgumentResolver.java b/src/main/java/org/springframework/data/gemfire/function/DefaultFunctionArgumentResolver.java new file mode 100644 index 00000000..e50ff1bb --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/DefaultFunctionArgumentResolver.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2012 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.function; + +import com.gemstone.gemfire.cache.execute.FunctionContext; + +/** + * @author David Turanski + * + */ +public class DefaultFunctionArgumentResolver implements FunctionArgumentResolver { + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.FunctionArgumentResolver#resolveFunctionArguments(com.gemstone.gemfire.cache.execute.FunctionContext) + */ + @Override + public Object[] resolveFunctionArguments(FunctionContext functionContext) { + + Object[] args = (functionContext.getArguments().getClass().isArray()) ? (Object[]) functionContext + .getArguments() : new Object[] { functionContext.getArguments() }; + + return args; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/FunctionArgumentResolver.java b/src/main/java/org/springframework/data/gemfire/function/FunctionArgumentResolver.java new file mode 100644 index 00000000..346616e3 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/FunctionArgumentResolver.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2012 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.function; + +import com.gemstone.gemfire.cache.execute.FunctionContext; + +/** + * Strategy Interface for resolving function invocation arguments, given a {@link FunctionContext} + * @author David Turanski + * + */ +public interface FunctionArgumentResolver { + public Object[] resolveFunctionArguments(FunctionContext functionContext); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java b/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java new file mode 100644 index 00000000..34ce2ce5 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/FunctionContextInjectingArgumentResolver.java @@ -0,0 +1,140 @@ +/* + * Copyright 2002-2012 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.function; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.GemfireFunctionUtils; +import org.springframework.data.gemfire.function.config.RegionData; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.execute.RegionFunctionContext; +import com.gemstone.gemfire.cache.partition.PartitionRegionHelper; + + +/** + * @author David Turanski + * + */ +public class FunctionContextInjectingArgumentResolver extends DefaultFunctionArgumentResolver { + + private static Log logger = LogFactory.getLog(FunctionContextInjectingArgumentResolver.class); + + private final int regionParameterPosition; + private final int filterParameterPosition; + private final int functionContextParameterPosition; + private final Method method; + + public FunctionContextInjectingArgumentResolver(Method method) { + + this.method = method; + int annotatedRegionDataParameterPosition = GemfireFunctionUtils.getAnnotationParameterPosition(method, RegionData.class, new Class[]{Map.class}); + int regionTypeParameterPosition = getArgumentTypePosition(method,Region.class); + + if (annotatedRegionDataParameterPosition >=0 && regionTypeParameterPosition >= 0) { + Assert.isTrue(annotatedRegionDataParameterPosition == regionTypeParameterPosition, + String.format("Function method signature for method %s cannot contain an @RegionData parameter and a different Region type parameter", method.getName())); + } + + int tempRegionParameterPosition = -1; + + if (annotatedRegionDataParameterPosition >=0 ) { + tempRegionParameterPosition = annotatedRegionDataParameterPosition; + } else if (regionTypeParameterPosition >=0) { + tempRegionParameterPosition = regionTypeParameterPosition; + } + + regionParameterPosition = tempRegionParameterPosition; + filterParameterPosition = GemfireFunctionUtils.getAnnotationParameterPosition(method, Filter.class, new Class[]{Set.class}); + functionContextParameterPosition = getArgumentTypePosition(method,FunctionContext.class); + + + if (regionParameterPosition >=0 && filterParameterPosition >=0) { + Assert.state(regionParameterPosition != filterParameterPosition, "region parameter and filter parameter must be different"); + } + + } + + @Override + public Object[] resolveFunctionArguments(FunctionContext functionContext) { + + Object[] args = super.resolveFunctionArguments(functionContext); + + if (functionContext instanceof RegionFunctionContext) { + if (this.regionParameterPosition >= 0) { + args = ArrayUtils.insert(args, regionParameterPosition, getRegionForContext((RegionFunctionContext)functionContext)); + } + + if (this.filterParameterPosition >= 0) { + args = ArrayUtils.insert(args, filterParameterPosition, ((RegionFunctionContext)functionContext).getFilter()); + } + + if (this.functionContextParameterPosition >= 0) { + args = ArrayUtils.insert(args, functionContextParameterPosition, functionContext); + } + + } + + Assert.isTrue(args.length == method.getParameterTypes().length, + String.format("wrong number of arguments for method %s. Expected :%d, actual: %d", method.getName(), + method.getParameterTypes().length, args.length)); + + + return args; + + } + + /* + * @param regionFunctionContext + * @return + */ + private static Region getRegionForContext(RegionFunctionContext regionFunctionContext) { + + Region region = regionFunctionContext.getDataSet(); + if (PartitionRegionHelper.isPartitionedRegion(region)) { + if (logger.isDebugEnabled()) { + logger.debug("this is a partitioned region - filtering local data for context"); + } + region = PartitionRegionHelper.getLocalDataForContext(regionFunctionContext); + } + if (logger.isDebugEnabled()) { + logger.debug("region contains " + region.size() + " items"); + } + return region; + } + + private static int getArgumentTypePosition(Method method, Class requiredType) { + int position = -1; + int i = 0; + for (Class clazz: method.getParameterTypes()) { + if (requiredType.equals(clazz)) { + Assert.state(position < 0, String.format("Method %s signature cannot contain more than one parameter of type %s." + ,method.getName(),requiredType.getName())); + position = i; + } + i++; + } + return position; + + } + + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionOperations.java b/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionOperations.java deleted file mode 100644 index 618fd082..00000000 --- a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionOperations.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import java.io.Serializable; -import java.util.List; -import java.util.Set; - -import com.gemstone.gemfire.cache.execute.Function; - -/** - * @author David Turanski - * - * @param - */ -public interface GemfireFunctionOperations { - - public abstract List executeOnRegion(Function function, String regionId, Serializable... args); - - public abstract T executeOnRegionAndExtract(Function function, String regionId, Serializable... args); - - public abstract List executeOnRegion(Function function, String regionId, Set keys, Serializable... args); - - public abstract List executeOnRegion(String functionId, String regionId, Serializable... args); - - public abstract List executeOnRegion(String functionId, String regionId, Set keys, Serializable... args); - - public abstract T executeOnRegion(String regionId, GemfireFunctionCallback callback); - - public abstract List executeOnServers(Function function, Serializable... args); - - public abstract List executeOnServers(String functionId, Serializable... args); - - public abstract T executeOnServers(GemfireFunctionCallback callback); - -} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBean.java b/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBean.java deleted file mode 100644 index dfed26d5..00000000 --- a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBean.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -import com.gemstone.gemfire.cache.execute.FunctionException; - -/** - * Creates a Proxy to a delegate that is executed as a Gemfire remote function - * using {@link MethodInvokingFunction}. Also, adds the {@link FilterAware} - * - * interface to the proxy which is used to set a data filter when execution is - * performed on a partitioned region. - * - * @author David Turanski - * - */ -public class GemfireFunctionProxyFactoryBean implements FactoryBean, MethodInterceptor, BeanClassLoaderAware { - private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private final Class serviceInterface; - - private volatile Object serviceProxy; - - private volatile boolean initialized; - - private final String delegateClassName; - - private final ThreadLocal> filter; - - private boolean methodInvokingFunctionRegistered; - - private volatile String regionName; - - private final GemfireFunctionOperations gemfireFunctionOperations; - - private static Log logger = LogFactory.getLog(GemfireFunctionProxyFactoryBean.class); - - /** - * - * @param serviceInterface the proxy interface - * @param delegateClassName the name of the implementation class - * @param gemfireFunctionOperations a strategy interface, normally a - * {@link GemfireFunctionTemplate} - */ - public GemfireFunctionProxyFactoryBean(Class serviceInterface, String delegateClassName, - GemfireFunctionOperations gemfireFunctionOperations) { - this.delegateClassName = delegateClassName; - Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); - Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); - this.serviceInterface = serviceInterface; - - Assert.notNull(gemfireFunctionOperations); - this.gemfireFunctionOperations = gemfireFunctionOperations; - this.filter = new ThreadLocal>(); - } - - // @Override - public void setBeanClassLoader(ClassLoader classLoader) { - beanClassLoader = classLoader; - } - - // @Override - @SuppressWarnings("unchecked") - public Object invoke(MethodInvocation invocation) throws Throwable { - - if (AopUtils.isToStringMethod(invocation.getMethod())) { - return "Gemfire function proxy for service interface [" + this.serviceInterface + "]"; - } - - if (logger.isDebugEnabled()) { - logger.debug("invoking method " + invocation.getMethod().getName()); - } - - if (isSetFilterMethod(invocation.getMethod())) { - setFilter((Set) invocation.getArguments()[0]); - return getObject(); - } - - RemoteMethodInvocation remoteInvocation = new RemoteMethodInvocation(this.delegateClassName, invocation - .getMethod().getName(), convertArgsToSerializable(invocation.getArguments())); - - List results = null; - - if (this.methodInvokingFunctionRegistered) { - if (this.regionName != null) { - - results = this.gemfireFunctionOperations.executeOnRegion(MethodInvokingFunction.FUNCTION_ID, - this.regionName, this.getFilter(), remoteInvocation); - } - else { - if (this.getFilter() != null) { - logger.warn("No region is specified. Filter has no effect on a data independent function execution"); - } - results = this.gemfireFunctionOperations.executeOnServers(MethodInvokingFunction.FUNCTION_ID, - remoteInvocation); - } - - } - else { - if (this.regionName != null) { - results = this.gemfireFunctionOperations.executeOnRegion(new MethodInvokingFunction(), this.regionName, - this.getFilter(), remoteInvocation); - } - else { - if (this.getFilter() != null) { - logger.warn("No region is specified. Filter has no effect on a data independent function execution"); - } - results = this.gemfireFunctionOperations.executeOnServers(new MethodInvokingFunction(), - remoteInvocation); - } - } - - return extractResult(results, invocation.getMethod().getReturnType()); - } - - // @Override - public Object getObject() throws Exception { - if (this.serviceProxy == null) { - this.onInit(); - Assert.notNull(this.serviceProxy, "failed to initialize proxy"); - } - return this.serviceProxy; - } - - // @Override - public Class getObjectType() { - return (this.serviceInterface != null ? this.serviceInterface : null); - } - - // @Override - public boolean isSingleton() { - return true; - } - - protected Set getFilter() { - return filter.get(); - } - - protected void setFilter(Set filter) { - this.filter.set(filter); - } - - /** - * Set to true id {@link MethodInvokingFunction} is a registered function. - * If registered, invocations will not create and transport a new instance - * of the function to the cache server(s). - * @param methodInvokingFunctionRegistered - */ - public void setMethodInvokingFunctionRegistered(boolean methodInvokingFunctionRegistered) { - this.methodInvokingFunctionRegistered = methodInvokingFunctionRegistered; - } - - /** - * - * Optional region to use. If set, the function will execute onRegion, if - * null the function will execute onServers - * - * @param regionName - */ - public void setRegionName(String regionName) { - this.regionName = regionName; - } - - // TODO: Use something like cglib to implement setFilter() directly - // to eliminate the need to cast the proxy to FilterAware - protected void onInit() { - if (this.initialized) { - return; - } - ProxyFactory proxyFactory = new ProxyFactory(serviceInterface, this); - proxyFactory.addInterface(FilterAware.class); - this.serviceProxy = proxyFactory.getProxy(this.beanClassLoader); - this.initialized = true; - } - - /* - * This tweek is needed to prevent an argument mismatch on the function - * invocation. - */ - private Serializable[] convertArgsToSerializable(Object[] array) { - return Arrays.copyOf(array, array.length, Serializable[].class); - } - - /* - * Match the result to the declared return type - */ - private Object extractResult(List results, Class returnType) { - Object result = null; - if (List.class.isAssignableFrom(returnType)) { - result = results; - } - else { - int nonNullItems = 0; - for (Object obj : results) { - if (obj != null) { - if (++nonNullItems > 1) { - throw new FunctionException("multiple results found for single valued return type"); - } - else { - result = obj; - } - } - } - } - if (logger.isDebugEnabled()) { - logger.debug("returning result as " + result.getClass().getName()); - } - return result; - } - - private static boolean isSetFilterMethod(Method method) { - try { - Method setFilterMethod = FilterAware.class.getMethod("setFilter", Set.class); - return method.equals(setFilterMethod); - } - catch (SecurityException e) { - } - catch (NoSuchMethodException e) { - } - return false; - } - -} diff --git a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionTemplate.java deleted file mode 100644 index e354019b..00000000 --- a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionTemplate.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import java.io.Serializable; -import java.util.List; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - -import com.gemstone.gemfire.cache.Region; -import com.gemstone.gemfire.cache.RegionService; -import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; -import com.gemstone.gemfire.cache.execute.FunctionService; - -/** - * @author David Turanski - * - */ -public class GemfireFunctionTemplate implements InitializingBean, GemfireFunctionOperations { - /** Logger available to subclasses */ - protected final Log log = LogFactory.getLog(getClass()); - private RegionService cache; - private long timeout; - - - /** - * - * @param cache - */ - public GemfireFunctionTemplate (RegionService cache) { - this.cache = cache; - afterPropertiesSet(); - } - - - public void afterPropertiesSet() { - } - - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegion(com.gemstone.gemfire.cache.execute.Function, java.lang.String, java.io.Serializable) - */ - public List executeOnRegion(Function function, String regionId, Serializable... args) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - RegionFunctionExecution execution = new RegionFunctionExecution(region, function, args); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegionAndExtract(com.gemstone.gemfire.cache.execute.Function, java.lang.String, java.io.Serializable) - */ - public T executeOnRegionAndExtract(Function function, String regionId, Serializable... args) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - RegionFunctionExecution execution = new RegionFunctionExecution(region, function, args); - execution.setTimeout(this.timeout); - return execution.executeAndExtract(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegion(com.gemstone.gemfire.cache.execute.Function, java.lang.String, java.util.Set, java.io.Serializable) - */ - public List executeOnRegion(Function function, String regionId, Set keys, Serializable... args) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - - RegionFunctionExecution execution = new RegionFunctionExecution(region, function, args); - execution.setKeys(keys); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegion(java.lang.String, java.lang.String, java.io.Serializable) - */ - public List executeOnRegion(String functionId, String regionId, Serializable... args) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - - RegionFunctionExecution execution = new RegionFunctionExecution(region, functionId, args); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegion(java.lang.String, java.lang.String, java.util.Set, java.io.Serializable) - */ - public List executeOnRegion(String functionId, String regionId, Set keys, Serializable... args) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - - RegionFunctionExecution execution = new RegionFunctionExecution(region, functionId, args); - execution.setKeys(keys); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnRegion(java.lang.String, org.springframework.data.gemfire.function.GemfireFunctionCallback) - */ - public T executeOnRegion(String regionId, GemfireFunctionCallback callback ) { - Region region = getRegion(regionId); - Assert.notNull(region,"Region '" + regionId + "' not found"); - Execution execution = FunctionService.onRegion(region); - return callback.doInGemfire(execution); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnServers(com.gemstone.gemfire.cache.execute.Function, java.io.Serializable) - */ - public List executeOnServers(Function function, Serializable... args) { - ServersFunctionExecution execution = new ServersFunctionExecution(this.cache, function, args); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnServers(java.lang.String, java.io.Serializable) - */ - public List executeOnServers(String functionId, Serializable... args) { - ServersFunctionExecution execution = new ServersFunctionExecution(this.cache, functionId, args); - execution.setTimeout(this.timeout); - return execution.execute(); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.GemfireFunctionOperations#executeOnServers(org.springframework.data.gemfire.function.GemfireFunctionCallback) - */ - public T executeOnServers(GemfireFunctionCallback callback ) { - Execution execution = FunctionService.onServers(this.cache); - return callback.doInGemfire(execution); - } - - - public Region getRegion(String regionId) { - return this.cache.getRegion(regionId); - } - - - public void setTimeout(long timeout) { - this.timeout = timeout; - } - - - public long getTimeout() { - return timeout; - } - - - -} diff --git a/src/main/java/org/springframework/data/gemfire/function/MemberFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/MemberFunctionExecution.java deleted file mode 100644 index eba3c959..00000000 --- a/src/main/java/org/springframework/data/gemfire/function/MemberFunctionExecution.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import java.io.Serializable; - -import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; -import com.gemstone.gemfire.cache.execute.FunctionService; -import com.gemstone.gemfire.distributed.DistributedSystem; - -/** - * @author David Turanski - * - */ -public class MemberFunctionExecution extends FunctionExecution { - - - private final DistributedSystem distributedSystem; - - /** - * @param functionId - * @param args - */ - public MemberFunctionExecution(DistributedSystem distributedSystem, Function function, Serializable... args) { - super(function, args); - this.distributedSystem = distributedSystem; - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.FunctionExecution#getExecution() - */ - @Override - protected Execution getExecution() { - return FunctionService.onMember(this.distributedSystem, this.distributedSystem.getDistributedMember()); - } - - - - -} diff --git a/src/main/java/org/springframework/data/gemfire/function/MethodInvokingFunction.java b/src/main/java/org/springframework/data/gemfire/function/MethodInvokingFunction.java index eb1183c0..f64b0e25 100644 --- a/src/main/java/org/springframework/data/gemfire/function/MethodInvokingFunction.java +++ b/src/main/java/org/springframework/data/gemfire/function/MethodInvokingFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 diff --git a/src/main/java/org/springframework/data/gemfire/function/PojoFunctionWrapper.java b/src/main/java/org/springframework/data/gemfire/function/PojoFunctionWrapper.java index 4f6b10a8..96654cf4 100644 --- a/src/main/java/org/springframework/data/gemfire/function/PojoFunctionWrapper.java +++ b/src/main/java/org/springframework/data/gemfire/function/PojoFunctionWrapper.java @@ -12,11 +12,10 @@ */ package org.springframework.data.gemfire.function; -import java.io.Serializable; + import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; -import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,23 +24,21 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; -import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.execute.Function; import com.gemstone.gemfire.cache.execute.FunctionContext; -import com.gemstone.gemfire.cache.execute.RegionFunctionContext; import com.gemstone.gemfire.cache.execute.ResultSender; -import com.gemstone.gemfire.cache.partition.PartitionRegionHelper; -import com.gemstone.gemfire.internal.util.ArrayUtils; /** * Invokes a POJO's given method as a Gemfire remote function. * If the POJO has a constructor that takes a Map, and the function context is Region, the * region will be injected. The delegate class name, the method name, and the method arguments - * are part of a remote function invocation, therefore all arguments must be serializable. + * are part of a remote function invocation, therefore all arguments must be serializable + * or an alternate serialization method must be used. * The delegate class must be the class path of the remote cache(s) * @author David Turanski * */ + @SuppressWarnings("serial") public class PojoFunctionWrapper implements Function { @@ -53,9 +50,13 @@ public class PojoFunctionWrapper implements Function { private final Object target; private final Method method; private final String id; - private volatile Integer regionParameterPosition; + + private final FunctionArgumentResolver functionArgumentResolver; public PojoFunctionWrapper(Object target, Method method, String id) { + + this.functionArgumentResolver = new FunctionContextInjectingArgumentResolver(method); + this.id = StringUtils.hasText(id) ? id : ClassUtils.getQualifiedMethodName(method); this.target = target; this.method = method; @@ -95,31 +96,13 @@ public class PojoFunctionWrapper implements Function { this.optimizeForWrite = optimizeForWrite; } - public void setRegionParameterPosition(int regionParameterPosition) { - this.regionParameterPosition = regionParameterPosition; - } - //@Override public void execute(FunctionContext functionContext) { + + Object[] args = this.functionArgumentResolver.resolveFunctionArguments(functionContext); - Object[] args = (functionContext.getArguments().getClass().isArray()) ? (Object[]) functionContext - .getArguments() : new Object[] { functionContext.getArguments() }; - - Serializable result = null; - - if (functionContext instanceof RegionFunctionContext) { - RegionFunctionContext regionFunctionContext = (RegionFunctionContext) functionContext; - Region region = getRegionForContext(regionFunctionContext); - //TODO: Not sure if filter is needed at this point - Set filter = regionFunctionContext.getFilter(); - //Insert the region into the associated position - if (this.regionParameterPosition != null) { - ArrayUtils.insert(args, regionParameterPosition, region); - } - - } else { - - } + + Object result = null; result = invokeTargetMethod(args); @@ -129,7 +112,7 @@ public class PojoFunctionWrapper implements Function { } - protected final Serializable invokeTargetMethod(Object[] args) { + protected final Object invokeTargetMethod(Object[] args) { if (logger.isDebugEnabled()) { logger.debug(String.format("about to invoke method %s on class %s as function %s", method.getName(), target @@ -141,54 +124,36 @@ public class PojoFunctionWrapper implements Function { } - return (Serializable) ReflectionUtils.invokeMethod(method, target, (Object[]) args); - } - - /* - * @param regionFunctionContext - * @return - */ - private Region getRegionForContext(RegionFunctionContext regionFunctionContext) { - - Region region = regionFunctionContext.getDataSet(); - if (PartitionRegionHelper.isPartitionedRegion(region)) { - if (logger.isDebugEnabled()) { - logger.debug("this is a partitioned region - filtering local data for context"); - } - region = PartitionRegionHelper.getLocalDataForContext(regionFunctionContext); - } - if (logger.isDebugEnabled()) { - logger.debug("region contains " + region.size() + " items"); - } - return region; + return (Object) ReflectionUtils.invokeMethod(method, target, (Object[]) args); } @SuppressWarnings("unchecked") - private void sendResults(ResultSender resultSender, Serializable result) { + private void sendResults(ResultSender resultSender, Object result) { if (result == null) { resultSender.lastResult(null); return; } - - Serializable lastItem = result; - - List results = null; + + List results = null; + if (ObjectUtils.isArray(result)) { - results = Arrays.asList((Serializable[]) result); + results = Arrays.asList((Object[]) result); + } else if (List.class.isAssignableFrom(result.getClass())) { - results = (List) result; + results = (List) result; } if (results != null) { int i = 0; - for (Serializable item : results) { + for (Object item : results) { if (i++ < results.size() - 1) { resultSender.sendResult(item); } else { - lastItem = item; + resultSender.lastResult(item); } } + } else { + resultSender.lastResult(result); } - resultSender.lastResult(lastItem); } } diff --git a/src/main/java/org/springframework/data/gemfire/function/RemoteMethodInvocation.java b/src/main/java/org/springframework/data/gemfire/function/RemoteMethodInvocation.java index 4ded54ad..585f9379 100644 --- a/src/main/java/org/springframework/data/gemfire/function/RemoteMethodInvocation.java +++ b/src/main/java/org/springframework/data/gemfire/function/RemoteMethodInvocation.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 diff --git a/src/main/java/org/springframework/data/gemfire/function/ServerFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/ServerFunctionExecution.java deleted file mode 100644 index faf54d15..00000000 --- a/src/main/java/org/springframework/data/gemfire/function/ServerFunctionExecution.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import java.io.Serializable; - -import com.gemstone.gemfire.cache.RegionService; -import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; -import com.gemstone.gemfire.cache.execute.FunctionService; - -/** - * @author David Turanski - * - */ -public class ServerFunctionExecution extends FunctionExecution { - - - private final RegionService regionService; - - /** - * - * @param regionService e.g., Cache,Client, or GemFireCache - * @param function - * @param args - */ - public ServerFunctionExecution(RegionService regionService, Function function, Serializable... args) { - super(function, args); - this.regionService = regionService; - } - - /** - * - * @param regionService e.g., Cache,Client, or GemFireCache - * @param functionId - * @param args - */ - public ServerFunctionExecution(RegionService regionService, String functionId, Serializable... args) { - super(functionId, args); - this.regionService = regionService; - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.FunctionExecution#getExecution() - */ - @Override - protected Execution getExecution() { - return FunctionService.onServer(this.regionService); - } -} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..637e43b2 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionBeanDefinitionBuilder.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.util.Assert; +/** + * Base class for function execution bean definition builders + * @author David Turanski + * + */ +abstract class AbstractFunctionExecutionBeanDefinitionBuilder { + + protected final Log log = LogFactory.getLog(this.getClass()); + protected final FunctionExecutionConfiguration configuration; + + + /** + * + * @param configuration the configuration values + */ + AbstractFunctionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + Assert.notNull(configuration); + this.configuration = configuration; + } + + /** + * Build the bean definition + * @param registry + * @return + */ + BeanDefinition build(BeanDefinitionRegistry registry) { + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getFunctionProxyFactoryBeanClass()); + + builder.addConstructorArgValue(configuration.getFunctionExecutionInterface()); + + BeanDefinitionBuilder functionTemplateBuilder = getGemfireOperationsBeanDefinitionBuilder(registry); + functionTemplateBuilder.setLazyInit(true); + + AbstractBeanDefinition functionTemplate = functionTemplateBuilder + .getBeanDefinition(); + + String functionTemplateName = BeanDefinitionReaderUtils.registerWithGeneratedName(functionTemplate, registry); + + builder.addConstructorArgReference(functionTemplateName); + +// builder.addConstructorArgValue(functionTemplate); + + + return builder.getBeanDefinition(); + + } + + /* + * Subclasses implement to specify the types to uses. + */ + protected abstract Class getFunctionProxyFactoryBeanClass(); + protected abstract BeanDefinitionBuilder getGemfireOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java new file mode 100644 index 00000000..8f844542 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java @@ -0,0 +1,204 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * Annotation based configuration source for function executions + * + * @author David Turanski + * + */ +class AnnotationFunctionExecutionConfigurationSource implements FunctionExecutionConfigurationSource { + private static Log logger = LogFactory.getLog(AnnotationFunctionExecutionConfigurationSource.class); + + private static final String BASE_PACKAGES = "basePackages"; + private static final String BASE_PACKAGE_CLASSES = "basePackageClasses"; + + private final AnnotationMetadata metadata; + private final AnnotationAttributes attributes; + private static Set> functionExecutionAnnotationTypes; + + static { + functionExecutionAnnotationTypes = new HashSet>(); + functionExecutionAnnotationTypes.add(OnRegion.class); + functionExecutionAnnotationTypes.add(OnServer.class); + functionExecutionAnnotationTypes.add(OnServers.class); + functionExecutionAnnotationTypes.add(OnMember.class); + functionExecutionAnnotationTypes.add(OnMembers.class); + } + + + /** + * Creates a new {@link AnnotationFunctionExecutionConfigurationSource} from the given {@link AnnotationMetadata} and + * annotation. + * + * @param metadata must not be {@literal null}. + */ + AnnotationFunctionExecutionConfigurationSource(AnnotationMetadata metadata) { + + Assert.notNull(metadata); + + this.attributes = new AnnotationAttributes(metadata.getAnnotationAttributes(EnableGemfireFunctionExecutions.class.getName())); + this.metadata = metadata; + + + + } + + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getSource() + */ + @Override + public Object getSource() { + // TODO Auto-generated method stub + return this.metadata; + } + + static Set> getFunctionExecutionAnnotationTypes() { + return functionExecutionAnnotationTypes; + } + + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getBasePackages() + */ + @Override + public Iterable getBasePackages() { + String[] value = attributes.getStringArray("value"); + String[] basePackages = attributes.getStringArray(BASE_PACKAGES); + Class[] basePackageClasses = attributes.getClassArray(BASE_PACKAGE_CLASSES); + + // Default configuration - return package of annotated class + if (value.length == 0 && basePackages.length == 0 && basePackageClasses.length == 0) { + String className = metadata.getClassName(); + return Collections.singleton(className.substring(0, className.lastIndexOf('.'))); + } + + Set packages = new HashSet(); + packages.addAll(Arrays.asList(value)); + packages.addAll(Arrays.asList(basePackages)); + + for (Class typeName : basePackageClasses) { + packages.add(ClassUtils.getPackageName(typeName)); + } + + return packages; + } + + @Override + public Collection getCandidates(ResourceLoader loader) { + ClassPathScanningCandidateComponentProvider scanner = new FunctionExecutionComponentProvider(getIncludeFilters(),functionExecutionAnnotationTypes); + scanner.setResourceLoader(loader); + + for (TypeFilter filter : getExcludeFilters()) { + scanner.addExcludeFilter(filter); + } + + Set result = new HashSet(); + + for (String basePackage : getBasePackages()) { + logger.debug("scanning package " + basePackage); + Collection components = scanner.findCandidateComponents(basePackage); + for (BeanDefinition definition : components) { + result.add((ScannedGenericBeanDefinition)definition); + } + } + + return result; + } + + + protected Iterable getIncludeFilters() { + return parseFilters("includeFilters"); + } + + + protected Iterable getExcludeFilters() { + return parseFilters("excludeFilters"); + } + + private Set parseFilters(String attributeName) { + + Set result = new HashSet(); + AnnotationAttributes[] filters = attributes.getAnnotationArray(attributeName); + + for (AnnotationAttributes filter : filters) { + result.addAll(typeFiltersFor(filter)); + } + + return result; + } + + /** + * Copy of {@code ComponentScanAnnotationParser#typeFiltersFor}. + * + * @param filterAttributes + * @return + */ + private List typeFiltersFor(AnnotationAttributes filterAttributes) { + List typeFilters = new ArrayList(); + FilterType filterType = filterAttributes.getEnum("type"); + + for (Class filterClass : filterAttributes.getClassArray("value")) { + switch (filterType) { + case ANNOTATION: + Assert.isAssignable(Annotation.class, filterClass, "An error occured when processing a @ComponentScan " + + "ANNOTATION type filter: "); + @SuppressWarnings("unchecked") + Class annoClass = (Class) filterClass; + typeFilters.add(new AnnotationTypeFilter(annoClass)); + break; + case ASSIGNABLE_TYPE: + typeFilters.add(new AssignableTypeFilter(filterClass)); + break; + case CUSTOM: + Assert.isAssignable(TypeFilter.class, filterClass, "An error occured when processing a @ComponentScan " + + "CUSTOM type filter: "); + typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class)); + break; + default: + throw new IllegalArgumentException("unknown filter type " + filterType); + } + } + return typeFilters; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctionExecutions.java b/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctionExecutions.java new file mode 100644 index 00000000..94b182bf --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctionExecutions.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Import; + +/** + * Enables classpath scanning for interfaces annotated as GemFire function executions (function invocations). + * These include interfaces annotated with one of {code} @OnRegion, @OnServer, @OnServers, @OnMember, @OnMembers{code} + * + * @author David Turanski + * + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Import(FunctionExecutionBeanDefinitionRegistrar.class) +public @interface EnableGemfireFunctionExecutions { + + /** + * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: + * {@code @EnableGemfireRepositories("org.my.pkg")} instead of + * {@code @EnableGemfireRepositories(basePackages="org.my.pkg")}. + */ + String[] value() default {}; + /** + * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this + * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. + */ + String[] basePackages() default {}; + + /** + * Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The + * package of each class specified will be scanned. Consider creating a special no-op marker class or interface in + * each package that serves no purpose other than being referenced by this attribute. + */ + Class[] basePackageClasses() default {}; + + /** + * Specifies which types are eligible for component scanning. Further narrows the set of candidate components from + * everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. + */ + Filter[] includeFilters() default {}; + + /** + * Specifies which types are not eligible for component scanning. + */ + Filter[] excludeFilters() default {}; +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctions.java b/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctions.java index 83830f6f..82d623d0 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctions.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/EnableGemfireFunctions.java @@ -19,9 +19,14 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Import; /** + * + * Enables Gemfire annotated function implementations. Causes the container to + * discover any beans that are annotated with {code} @GemfireFunction {code}, wrap them in + * a {@link PojoFunctionWrapper}, and register them with the cache. + * * @author David Turanski * */ @@ -29,36 +34,6 @@ import org.springframework.context.annotation.ComponentScan.Filter; @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited +@Import(GemfireFunctionPostBeanProcessorRegistrar.class) public @interface EnableGemfireFunctions { - /** - * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: - * {@code @EnableGemfireRepositories("org.my.pkg")} instead of - * {@code @EnableGemfireRepositories(basePackages="org.my.pkg")}. - */ - String[] value() default {}; - - /** - * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this - * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. - */ - String[] basePackages() default {}; - - /** - * Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The - * package of each class specified will be scanned. Consider creating a special no-op marker class or interface in - * each package that serves no purpose other than being referenced by this attribute. - */ - Class[] basePackageClasses() default {}; - - /** - * Specifies which types are eligible for component scanning. Further narrows the set of candidate components from - * everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. - */ - Filter[] includeFilters() default {}; - - /** - * Specifies which types are not eligible for component scanning. - */ - Filter[] excludeFilters() default {}; - } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/Filter.java b/src/main/java/org/springframework/data/gemfire/function/config/Filter.java new file mode 100644 index 00000000..1bdf5d0d --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/Filter.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * Used to inject a set of cache keys into a function execution, The annotated parameter must be of type + * {@link Set}. This is used by the function invocation to specify a set of keys of interest and also to define + * an additional parameter on the function implementation method containing the filter. + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.PARAMETER}) +public @interface Filter { +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionBuilderFactory.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionBuilderFactory.java new file mode 100644 index 00000000..b1dfbf50 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionBuilderFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2012 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.function.config; + +/** + * + * Maps the annotation type to the corresponding function execution bean definition builder + * @author David Turanski + * + */ +abstract class FunctionExecutionBeanDefinitionBuilderFactory { + + static AbstractFunctionExecutionBeanDefinitionBuilder newInstance(FunctionExecutionConfiguration configuration) { + String functionExectionAnnotation = configuration.getAnnotationType(); + if (functionExectionAnnotation.equals(OnRegion.class.getName())) { + return new OnRegionExecutionBeanDefinitionBuilder(configuration); + } + if (functionExectionAnnotation.equals(OnServer.class.getName())) { + return new OnServerExecutionBeanDefinitionBuilder(configuration); + } + if (functionExectionAnnotation.equals(OnServers.class.getName())) { + return new OnServersExecutionBeanDefinitionBuilder(configuration); + } + if (functionExectionAnnotation.equals(OnMember.class.getName())) { + return new OnMemberExecutionBeanDefinitionBuilder(configuration); + } + if (functionExectionAnnotation.equals(OnMembers.class.getName())) { + return new OnMembersExecutionBeanDefinitionBuilder(configuration); + } + return null; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java new file mode 100644 index 00000000..971bfa00 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * {@link ImportBeanDefinitionRegistrar} for {code} @EnableGemfireFunctionExecutions {code} + * Scans for interfaces annotated with one of {code} @OnRegion, @OnServer, @OnServers, @OnMember, @OnMembers {code} + * @author David Turanski + * + */ +public class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { + + private static Log logger = LogFactory.getLog(FunctionExecutionBeanDefinitionRegistrar.class); + /* (non-Javadoc) + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry) + */ + @Override + public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { + + logger.debug("registering bean definitions..."); + + ResourceLoader resourceLoader = new DefaultResourceLoader(); + AnnotationFunctionExecutionConfigurationSource configurationSource = new AnnotationFunctionExecutionConfigurationSource( + annotationMetadata); + + Set functionExecutionAnnotationTypes = new HashSet( + AnnotationFunctionExecutionConfigurationSource.getFunctionExecutionAnnotationTypes().size()); + for (Class annotation : AnnotationFunctionExecutionConfigurationSource.getFunctionExecutionAnnotationTypes()) { + functionExecutionAnnotationTypes.add(annotation.getName()); + } + + for (ScannedGenericBeanDefinition beanDefinition : configurationSource.getCandidates(resourceLoader)) { + + String functionExecutionAnnotation = getFunctionExecutionAnnotation(beanDefinition, + functionExecutionAnnotationTypes); + + Assert.notNull(functionExecutionAnnotation); + + String beanName = (String) beanDefinition.getMetadata() + .getAnnotationAttributes(functionExecutionAnnotation).get("id"); + + if (!StringUtils.hasLength(beanName)) { + beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, registry); + } + AbstractFunctionExecutionBeanDefinitionBuilder builder = FunctionExecutionBeanDefinitionBuilderFactory + .newInstance(new FunctionExecutionConfiguration(beanDefinition, functionExecutionAnnotation)); + + registry.registerBeanDefinition(beanName, builder.build(registry)); + } + + } + + private String getFunctionExecutionAnnotation(ScannedGenericBeanDefinition beanDefinition, + Set functionExecutionAnnotationTypes) { + + Set annotationTypes = beanDefinition.getMetadata().getAnnotationTypes(); + + String functionExecutionAnnotation = null; + + for (String annotation : annotationTypes) { + if (functionExecutionAnnotationTypes.contains(annotation)) { + Assert.isNull(functionExecutionAnnotation, String.format( + "interface %s contains multiple function execution annotations: %s, %s", + beanDefinition.getBeanClassName(), functionExecutionAnnotation, annotation)); + functionExecutionAnnotation = annotation; + } + } + + return functionExecutionAnnotation; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProvider.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProvider.java new file mode 100644 index 00000000..f04c4bf2 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProvider.java @@ -0,0 +1,218 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.data.gemfire.function.execution.FunctionExecution; +import org.springframework.util.Assert; + +/** + * Custom {@link ClassPathScanningCandidateComponentProvider} scanning for interfaces annotated for + * function execution + * + * @author David Turanski + */ +class FunctionExecutionComponentProvider extends ClassPathScanningCandidateComponentProvider { + + + private final Set> functionExecutionAnnotationTypes; + + /** + * Creates a new {@link FunctionExecutionComponentProvider} using the given {@link TypeFilter} to include components to be + * picked up. + * + * @param includeFilters the {@link TypeFilter}s to select function execution interfaces to consider, must not be + * {@literal null}. + */ + public FunctionExecutionComponentProvider(Iterable includeFilters , Set> functionExecutionAnnotationTypes) { + + super(false); + + this.functionExecutionAnnotationTypes = functionExecutionAnnotationTypes; + Assert.notNull(includeFilters); + + if (includeFilters.iterator().hasNext()) { + for (TypeFilter filter : includeFilters) { + addIncludeFilter(filter); + } + } else { + for (Class annotation: this.functionExecutionAnnotationTypes) { + super.addIncludeFilter(new AnnotationTypeFilter(annotation, true, true)); + } + } + } + + /** + * Custom extension of {@link #addIncludeFilter(TypeFilter)} to extend the added {@link TypeFilter}. For the + * {@link TypeFilter} handed we'll have two filters registered: one additionally enforcing the + * {@link FunctionExecutionDefinition} annotation, the other one forcing the extension of {@link FunctionExecution}. + * + * @see ClassPathScanningCandidateComponentProvider#addIncludeFilter(TypeFilter) + */ + @Override + public void addIncludeFilter(TypeFilter includeFilter) { + + List filterPlusInterface = new ArrayList(); + filterPlusInterface.add(includeFilter); + + super.addIncludeFilter(new AllTypeFilter(filterPlusInterface)); + + List filterPlusAnnotation = new ArrayList(); + filterPlusAnnotation.add(includeFilter); + for (Class annotation: this.functionExecutionAnnotationTypes) { + filterPlusAnnotation.add(new AnnotationTypeFilter(annotation, true, true)); + } + + super.addIncludeFilter(new AllTypeFilter(filterPlusAnnotation)); + } + + /* + * (non-Javadoc) + * @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent(org.springframework.beans.factory.annotation.AnnotatedBeanDefinition) + */ + @Override + protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { + + boolean isTopLevelType = !beanDefinition.getMetadata().hasEnclosingClass(); + + return isTopLevelType; + } + + + // Copy of Spring's AnnotationTypeFilter until SPR-8336 gets resolved. + + /** + * A simple filter which matches classes with a given annotation, checking inherited annotations as well. + *

+ * The matching logic mirrors that of Class.isAnnotationPresent(). + * + * @author Mark Fisher + * @author Ramnivas Laddad + * @author Juergen Hoeller + * @since 2.5 + */ + private static class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter { + + private final Class annotationType; + + private final boolean considerMetaAnnotations; + + /** + * Create a new AnnotationTypeFilter for the given annotation type. This filter will also match meta-annotations. To + * disable the meta-annotation matching, use the constructor that accepts a ' considerMetaAnnotations' + * argument. The filter will not match interfaces. + * + * @param annotationType the annotation type to match + */ + @SuppressWarnings("unused") + public AnnotationTypeFilter(Class annotationType) { + this(annotationType, true); + } + + /** + * Create a new AnnotationTypeFilter for the given annotation type. The filter will not match interfaces. + * + * @param annotationType the annotation type to match + * @param considerMetaAnnotations whether to also match on meta-annotations + */ + public AnnotationTypeFilter(Class annotationType, boolean considerMetaAnnotations) { + this(annotationType, considerMetaAnnotations, false); + } + + /** + * Create a new {@link AnnotationTypeFilter} for the given annotation type. + * + * @param annotationType the annotation type to match + * @param considerMetaAnnotations whether to also match on meta-annotations + * @param considerInterfaces whether to also match interfaces + */ + public AnnotationTypeFilter(Class annotationType, boolean considerMetaAnnotations, + boolean considerInterfaces) { + super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces); + this.annotationType = annotationType; + this.considerMetaAnnotations = considerMetaAnnotations; + } + + @Override + protected boolean matchSelf(MetadataReader metadataReader) { + AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); + return metadata.hasAnnotation(this.annotationType.getName()) + || (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())); + } + + @Override + protected Boolean matchSuperClass(String superClassName) { + if (Object.class.getName().equals(superClassName)) { + return Boolean.FALSE; + } else if (superClassName.startsWith("java.")) { + try { + Class clazz = getClass().getClassLoader().loadClass(superClassName); + return (clazz.getAnnotation(this.annotationType) != null); + } catch (ClassNotFoundException ex) { + // Class not found - can't determine a match that way. + } + } + return null; + } + } + + /** + * Helper class to create a {@link TypeFilter} that matches if all the delegates match. + * + * @author Oliver Gierke + */ + private static class AllTypeFilter implements TypeFilter { + + private final List delegates; + + /** + * Creates a new {@link AllTypeFilter} to match if all the given delegates match. + * + * @param delegates must not be {@literal null}. + */ + public AllTypeFilter(List delegates) { + + Assert.notNull(delegates); + this.delegates = delegates; + } + + /* + * (non-Javadoc) + * @see org.springframework.core.type.filter.TypeFilter#match(org.springframework.core.type.classreading.MetadataReader, org.springframework.core.type.classreading.MetadataReaderFactory) + */ + public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { + + for (TypeFilter filter : delegates) { + if (!filter.match(metadataReader, metadataReaderFactory)) { + return false; + } + } + + return true; + } + } +} + diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfiguration.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfiguration.java new file mode 100644 index 00000000..10f6c6ef --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfiguration.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.util.Map; + +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.util.Assert; + +/** + * Function execution configuration used by bean definition builders + * + * @author David Turanski + * + */ +class FunctionExecutionConfiguration { + + private final Map attributes; + private Class functionExecutionInterface; + private final String annotationType; + + + FunctionExecutionConfiguration(ScannedGenericBeanDefinition beanDefinition, String annotationType) { + this.attributes = beanDefinition.getMetadata().getAnnotationAttributes(annotationType,true); + + try { + this.functionExecutionInterface = beanDefinition.resolveBeanClass(beanDefinition.getClass().getClassLoader()); + Assert.isTrue(functionExecutionInterface.isInterface(), + String.format("The annotation %s only applies to an interface. It is not valid for the type %s", + annotationType, functionExecutionInterface.getName())); + + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + this.annotationType = annotationType; + } + + Class getFunctionExecutionInterface() { + return this.functionExecutionInterface; + } + + Map getAttributes() { + return this.attributes; + } + + + Object getAttribute(String name) { + return attributes.get(name); + } + + String getAnnotationType() { + return this.annotationType; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java new file mode 100644 index 00000000..a7452a75 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.util.Collection; + +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.io.ResourceLoader; + +/** + * Interface for function execution configuration sources (e.g., annotation or XML configuration) to configure + * classpath scanning of annotated interfaces to implement proxies that invoke Gemfire functions + * + * @author David Turanski + * + */ +interface FunctionExecutionConfigurationSource { + /** + * Returns the actual source object that the configuration originated from. Will be used by the tooling to give visual + * feedback on where the repository instances actually come from. + * + * @return must not be {@literal null}. + */ + Object getSource(); + + /** + * Returns the base packages the repository interfaces shall be found under. + * + * @return must not be {@literal null}. + */ + Iterable getBasePackages(); + + /** + * Returns the scanned bean definitions + * + * @param loader + * @return + */ + Collection getCandidates(ResourceLoader loader); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionId.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionId.java new file mode 100644 index 00000000..e3a9ca4b --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionId.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to bind an interface method to a GemFire function id + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface FunctionId { + /** + * The name of the registered function + * @return the function id + */ + String value(); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunction.java b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunction.java index 9ba9c048..767a201c 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunction.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunction.java @@ -18,6 +18,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * + * Used to declare a concrete method as a GemFire function implementation + * * @author David Turanski * */ diff --git a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionBeanPostProcessor.java b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionBeanPostProcessor.java index 39f3d113..ad255fda 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionBeanPostProcessor.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionBeanPostProcessor.java @@ -12,7 +12,6 @@ */ package org.springframework.data.gemfire.function.config; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; @@ -24,13 +23,16 @@ import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; /** + * A {@link BeanPostProcessor} to discover components wired as function implementations. That is + * beans that contain methods annotated with {code} @GemfireFunction {code} + * * @author David Turanski * */ public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor { private static final String GEMFIRE_FUNCTION_ANNOTATION_NAME = GemfireFunction.class.getName(); - private static final String REGION_DATA_ANNOTATION_NAME = RegionData.class.getName(); + /* (non-Javadoc) * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String) @@ -45,7 +47,14 @@ public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor { */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - + + registerAnyDeclaredGemfireFunctionMethods(bean); + + return bean; + } + + private void registerAnyDeclaredGemfireFunctionMethods (Object bean) { + Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass()); for (Method method: methods) { @@ -53,34 +62,9 @@ public class GemfireFunctionBeanPostProcessor implements BeanPostProcessor { if (annotation != null) { Assert.isTrue(Modifier.isPublic(method.getModifiers()),"The method " + method.getName()+ " annotated with" + GEMFIRE_FUNCTION_ANNOTATION_NAME+ " must be public"); Map attributes = AnnotationUtils.getAnnotationAttributes(annotation,false,true); - - processParameterAnnotations(method); - GemfireFunctionUtils.registerFunctionForPojoMethod(bean, method, attributes, false); - } - } - - return bean; - } - - private void processParameterAnnotations(Method method) { - Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - if (parameterAnnotations.length == 0) { - return; - } - - Class[] paramTypes = method.getParameterTypes(); - - for (int i=0; i< parameterAnnotations.length; i++) { - Annotation[] annotations = parameterAnnotations[i]; - if (annotations.length > 0) { - System.out.println("found annotations for parameter in position " + i + " " + paramTypes[i] ); - for (Annotation annotation:annotations) { - System.out.println("Annotation type:" + annotation.annotationType().getName()); - } } - } - } + } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionPostBeanProcessorRegistrar.java b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionPostBeanProcessorRegistrar.java new file mode 100644 index 00000000..1db23fa3 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionPostBeanProcessorRegistrar.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.type.AnnotationMetadata; + +/** + * and {@link ImportBeanDefinitionRegistrar} to register the {@link GemfireFunctionBeanPostProcessor} + * + * @author David Turanski + * + */ +public class GemfireFunctionPostBeanProcessorRegistrar implements ImportBeanDefinitionRegistrar { + + /* (non-Javadoc) + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry) + */ + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionUtils.java b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionUtils.java index b2cc0c11..ac8e4367 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionUtils.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/GemfireFunctionUtils.java @@ -12,35 +12,49 @@ */ package org.springframework.data.gemfire.function.config; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.gemfire.function.PojoFunctionWrapper; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; -import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.execute.FunctionService; /** + * * @author David Turanski * */ public abstract class GemfireFunctionUtils { private static Log log = LogFactory.getLog(GemfireFunctionUtils.class); - - public static void registerFunctionForPojoMethod(Object target, Method method, Map attributes, boolean overwrite) { - String id = attributes.containsKey("id") ? (String)attributes.get("id") : ""; - - PojoFunctionWrapper function = new PojoFunctionWrapper(target,method, id); - + + /** + * Wrap a target object and method in a GemFire Function and register the function to the {@link FunctionService} + * + * @param target the target object + * @param method the method bound to the function + * @param attributes function attributes + * @param overwrite if true, will replace the existing function + */ + public static void registerFunctionForPojoMethod(Object target, Method method, Map attributes, + boolean overwrite) { + String id = attributes.containsKey("id") ? (String) attributes.get("id") : ""; + + PojoFunctionWrapper function = new PojoFunctionWrapper(target, method, id); + if (attributes.containsKey("HA")) { - function.setHA((Boolean)attributes.get("HA")); - } - if (attributes.containsKey("optimizeForWrite")) { - function.setOptimizeForWrite((Boolean)attributes.get("optimizeForWrite")); - } - + function.setHA((Boolean) attributes.get("HA")); + } + if (attributes.containsKey("optimizeForWrite")) { + function.setOptimizeForWrite((Boolean) attributes.get("optimizeForWrite")); + } + if (FunctionService.isRegistered(function.getId())) { if (overwrite) { if (log.isDebugEnabled()) { @@ -49,7 +63,7 @@ public abstract class GemfireFunctionUtils { FunctionService.unregisterFunction(function.getId()); } } - if (!FunctionService.isRegistered(function.getId())){ + if (!FunctionService.isRegistered(function.getId())) { FunctionService.registerFunction(function); if (log.isDebugEnabled()) { log.debug("registered function " + function.getId()); @@ -60,4 +74,42 @@ public abstract class GemfireFunctionUtils { } } } + + /** + * Determine the order position of a an annotated method parameter + * + * @param method the {@link Method} instance + * @param targetAnnotationType the annotation + * @param requiredTypes an array of valid parameter types for the annotation + * @return the parameter position or -1 if the annotated parameter is not found + */ + public static int getAnnotationParameterPosition(Method method, Class targetAnnotationType, Class[] requiredTypes) { + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + if (parameterAnnotations.length > 0) { + int position = -1; + Class[] paramTypes = method.getParameterTypes(); + + List> requiredTypesList = Arrays.asList(requiredTypes); + + + for (int i = 0; i < parameterAnnotations.length; i++) { + Annotation[] annotations = parameterAnnotations[i]; + if (annotations.length > 0) { + for (Annotation annotation : annotations) { + if (annotation.annotationType().equals(targetAnnotationType)) { + Assert.state(position < 0, String.format("Method %s signature cannot contain more than one parameter annotated with type %s" + ,method.getName(),targetAnnotationType.getName())); + Assert.isTrue(requiredTypesList.contains(paramTypes[i]), String.format( + "Parameter annotated with %s must be one of type %s in method %s", targetAnnotationType.getName(), + StringUtils.arrayToCommaDelimitedString(requiredTypes), method.getName())); + position = i; + } + + } + } + } + return position; + } + return -1; + } } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..5e7a0d2e --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean; +import org.springframework.util.StringUtils; + +/** + * A base class for OnMember and OnMembers function execution bean definition builders. + * + * @author David Turanski + * + */ + abstract class MemberBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + public MemberBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + } + + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry) + */ + @Override + protected BeanDefinitionBuilder getGemfireOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) { + + BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(getGemfireOperationsClass()); + + String groups = (String)configuration.getAttribute("groups"); + + + if (StringUtils.hasText(groups)) { + functionTemplateBuilder.addConstructorArgValue(StringUtils.commaDelimitedListToStringArray(groups)); + } + + return functionTemplateBuilder; + } + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getFunctionProxyFactoryBeanClass() + */ + @Override + protected Class getFunctionProxyFactoryBeanClass() { + return GemfireFunctionProxyFactoryBean.class; + } + + protected abstract Class getGemfireOperationsClass(); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnMember.java b/src/main/java/org/springframework/data/gemfire/function/config/OnMember.java new file mode 100644 index 00000000..37eb3998 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnMember.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare an interface as a GemFire OnMember Function Execution + * + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface OnMember { + + /** + * The bean name and also the default name of the registered function, if single method on the interface. + * If multiple methods declared use the (@link FunctionId) annotation on each method + * @return the function id + */ + String id() default ""; + + + //TODO SpEL expression for DistributedMember? + + /** + * groups + */ + String groups() default ""; +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnMemberExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/OnMemberExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..7c067b17 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnMemberExecutionBeanDefinitionBuilder.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.data.gemfire.function.execution.GemfireOnMemberFunctionTemplate; + +/** + * + * @author David Turanski + * + */ +class OnMemberExecutionBeanDefinitionBuilder extends MemberBasedExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + OnMemberExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + // TODO Auto-generated constructor stub + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.MemberBasedExecutionBeanDefinitionBuilder#getGemfireOperationsClass() + */ + @Override + protected Class getGemfireOperationsClass() { + return GemfireOnMemberFunctionTemplate.class; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnMembers.java b/src/main/java/org/springframework/data/gemfire/function/config/OnMembers.java new file mode 100644 index 00000000..a46138e2 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnMembers.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare an interface as a GemFire OnMembers Function Execution + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface OnMembers { + + /** + * The bean name and also the default name of the registered function, if single method on the interface. + * If multiple methods declared use the (@link FunctionId) annotation on each method + * @return the function id + */ + String id() default ""; + + //TODO SpEL expression for DistributedMembers? + + /** + * groups + */ + String groups() default ""; +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnMembersExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/OnMembersExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..4decd7b4 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnMembersExecutionBeanDefinitionBuilder.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.data.gemfire.function.execution.GemfireOnMembersFunctionTemplate; + +/** + * @author David Turanski + * + */ +class OnMembersExecutionBeanDefinitionBuilder extends MemberBasedExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + OnMembersExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + // TODO Auto-generated constructor stub + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.MemberBasedExecutionBeanDefinitionBuilder#getGemfireOperationsClass() + */ + @Override + protected Class getGemfireOperationsClass() { + return GemfireOnMembersFunctionTemplate.class; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnRegion.java b/src/main/java/org/springframework/data/gemfire/function/config/OnRegion.java new file mode 100644 index 00000000..0dbad85a --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnRegion.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare an interface as a GemFire OnRegion Function Execution + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface OnRegion { + + /** + * The bean name and also the default name of the registered function, if single method on the interface. + * If multiple methods declared use the (@link FunctionId) annotation on each method + * @return the function id + */ + String id() default ""; + + /** + * The reference to the bean id of the region + * @return the region id + */ + String region(); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnRegionExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/OnRegionExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..52a87fcc --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnRegionExecutionBeanDefinitionBuilder.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.data.gemfire.function.execution.GemfireOnRegionFunctionTemplate; +import org.springframework.data.gemfire.function.execution.OnRegionFunctionProxyFactoryBean; + +/** + * @author David Turanski + * + */ +class OnRegionExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + OnRegionExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + } + + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry) + */ + @Override + protected BeanDefinitionBuilder getGemfireOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) { + BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(GemfireOnRegionFunctionTemplate.class); + functionTemplateBuilder.addConstructorArgReference((String)configuration.getAttribute("region")); + return functionTemplateBuilder; + } + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getFunctionProxyFactoryBeanClass() + */ + @Override + protected Class getFunctionProxyFactoryBeanClass() { + return OnRegionFunctionProxyFactoryBean.class; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnServer.java b/src/main/java/org/springframework/data/gemfire/function/config/OnServer.java new file mode 100644 index 00000000..f94ed1b9 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnServer.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare an interface as a GemFire OnServer Function Execution + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface OnServer { + + /** + * The bean name and also the default name of the registered function, if single method on the interface. + * If multiple methods declared use the (@link FunctionId) annotation on each method + * @return the function id + */ + String id() default ""; + + /** + * The pool bean id (optional) + * @return + */ + + String pool() default ""; + /** + * A reference to the cache + */ + String cache() default ""; + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnServerExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/OnServerExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..69e59014 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnServerExecutionBeanDefinitionBuilder.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.data.gemfire.function.execution.GemfireOnServerFunctionTemplate; + +/** + * @author David Turanski + * + */ +class OnServerExecutionBeanDefinitionBuilder extends ServerBasedExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + OnServerExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder#getGemfireOperationsClass() + */ + @Override + protected Class getGemfireOperationsClass() { + return GemfireOnServerFunctionTemplate.class; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnServers.java b/src/main/java/org/springframework/data/gemfire/function/config/OnServers.java new file mode 100644 index 00000000..271c2602 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnServers.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2012 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.function.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare an interface as a GemFire OnServers Function Execution + * @author David Turanski + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface OnServers { + + /** + * The bean name and also the default name of the registered function, if single method on the interface. + * If multiple methods declared use the (@link FunctionId) annotation on each method + * @return the function id + */ + String id() default ""; + + /** + * The pool bean name (optional) + * @return + */ + String pool() default ""; + + /** + * A reference to the cache + */ + String cache() default "gemfireCache"; +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/OnServersExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/OnServersExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..5f777933 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/OnServersExecutionBeanDefinitionBuilder.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.data.gemfire.function.execution.GemfireOnServersFunctionTemplate; + +/** + * @author David Turanski + * + */ +class OnServersExecutionBeanDefinitionBuilder extends ServerBasedExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + OnServersExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.ServerBasedExecutionBeanDefinitionBuilder#getGemfireOperationsClass() + */ + @Override + protected Class getGemfireOperationsClass() { + return GemfireOnServersFunctionTemplate.class; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/config/RegionData.java b/src/main/java/org/springframework/data/gemfire/function/config/RegionData.java index 92b9ae5d..ca813a02 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/RegionData.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/RegionData.java @@ -23,11 +23,11 @@ import java.lang.annotation.Target; * {@link Map}. The contents depends on the region configuration (for a partitioned region, this will * contain only entries for the local partition) * and any filters configured for the function context. + * * @author David Turanski * */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER}) public @interface RegionData { - String value() default ""; } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java new file mode 100644 index 00000000..abedfa9f --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2012 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.function.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.data.gemfire.config.GemfireConstants; +import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * @author David Turanski + * + */ +abstract class ServerBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { + + /** + * @param configuration + */ + ServerBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + super(configuration); + } + + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry) + */ + @Override + protected BeanDefinitionBuilder getGemfireOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) { + + BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(getGemfireOperationsClass()); + + String pool = (String)configuration.getAttribute("pool"); + String cache = (String)configuration.getAttribute("cache"); + + Assert.state(!(StringUtils.hasText(pool) && StringUtils.hasText(cache)), + String.format("invalid configuration for interface %s. Cannot specify both 'pool' and 'cache'", + configuration.getFunctionExecutionInterface().getName())); + + if (StringUtils.hasText(pool)) { + + functionTemplateBuilder.addConstructorArgReference(pool); + } else { + if (!StringUtils.hasText(cache)) { + cache = GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME; + } + + functionTemplateBuilder.addConstructorArgReference(cache); + } + return functionTemplateBuilder; + } + + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getFunctionProxyFactoryBeanClass() + */ + @Override + protected Class getFunctionProxyFactoryBeanClass() { + return GemfireFunctionProxyFactoryBean.class; + } + + protected abstract Class getGemfireOperationsClass(); +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java new file mode 100644 index 00000000..42350de0 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/AbstractFunctionTemplate.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.Function; + +/** + * + * The base class for Gemfire function templates used to invoke Gemfire functions + * @author David Turanski + * + */ +abstract class AbstractFunctionTemplate implements GemfireFunctionOperations { + + protected Log log = LogFactory.getLog(this.getClass()); + + protected long timeout; + + @Override + public Iterable execute(Function function, Object... args) { + FunctionExecution functionExecution = getFunctionExecution() + .setArgs(args) + .setFunction(function) + .setTimeout(timeout); + return execute(functionExecution); + } + + @Override + public T executeAndExtract(Function function, Object... args) { + FunctionExecution functionExecution = getFunctionExecution() + .setArgs(args) + .setFunction(function) + .setTimeout(timeout); + return executeAndExtract(functionExecution); + } + + @Override + public Iterable execute(String functionId, Object... args) { + FunctionExecution functionExecution = getFunctionExecution() + .setArgs(args) + .setFunctionId(functionId) + .setTimeout(timeout); + return execute(functionExecution); + } + + @Override + public T executeAndExtract(String functionId, Object... args) { + FunctionExecution functionExecution = getFunctionExecution() + .setArgs(args) + .setFunctionId(functionId) + .setTimeout(timeout); + return executeAndExtract(functionExecution); + } + + @Override + public T execute(GemfireFunctionCallback callback) { + Execution execution = getFunctionExecution().getExecution(); + return callback.doInGemfire(execution); + } + + + protected Iterable execute(FunctionExecution execution) { + execution.setTimeout(timeout); + return execution.execute(); + } + + protected T executeAndExtract(FunctionExecution execution) { + execution.setTimeout(timeout); + return execution.executeAndExtract(); + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + protected abstract FunctionExecution getFunctionExecution(); +} diff --git a/src/test/java/org/springframework/data/gemfire/function/foo/IFoo.java b/src/main/java/org/springframework/data/gemfire/function/execution/AllMembersFunctionExecution.java similarity index 59% rename from src/test/java/org/springframework/data/gemfire/function/foo/IFoo.java rename to src/main/java/org/springframework/data/gemfire/function/execution/AllMembersFunctionExecution.java index f9e18cd7..99d43a68 100644 --- a/src/test/java/org/springframework/data/gemfire/function/foo/IFoo.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/AllMembersFunctionExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -10,23 +10,20 @@ * 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.function.foo; +package org.springframework.data.gemfire.function.execution; -import java.util.List; -import java.util.Map; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; /** * @author David Turanski * */ -public interface IFoo { +public class AllMembersFunctionExecution extends FunctionExecution { + + @Override + protected Execution getExecution() { + return FunctionService.onMembers(); + } - public abstract Integer oneArg(String key); - - public abstract Integer twoArg(String akey, String bkey); - - public abstract List collections(List args); - - public abstract Map getMapWithNoArgs(); - -} \ No newline at end of file +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/DefaultFunctionExecutionMethodMetadata.java b/src/main/java/org/springframework/data/gemfire/function/execution/DefaultFunctionExecutionMethodMetadata.java new file mode 100644 index 00000000..35c93c6b --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/DefaultFunctionExecutionMethodMetadata.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.lang.reflect.Method; + + +/** + * @author David Turanski + * + */ +class DefaultFunctionExecutionMethodMetadata extends FunctionExecutionMethodMetadata { + + /** + * @param serviceInterface + */ + public DefaultFunctionExecutionMethodMetadata(Class serviceInterface) { + super(serviceInterface); + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.FunctionExecutionMethodMetadata#newMetadataInstance(java.lang.reflect.Method) + */ + @Override + protected MethodMetadata newMetadataInstance(Method method) { + return new MethodMetadata(method); + } + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/DefaultMemberFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/DefaultMemberFunctionExecution.java new file mode 100644 index 00000000..d5989f67 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/DefaultMemberFunctionExecution.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * @author David Turanski + * + */ +public class DefaultMemberFunctionExecution extends FunctionExecution { + + @Override + protected Execution getExecution() { + return FunctionService.onMember(); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/MembersFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/DistributedMemberFunctionExecution.java similarity index 50% rename from src/main/java/org/springframework/data/gemfire/function/MembersFunctionExecution.java rename to src/main/java/org/springframework/data/gemfire/function/execution/DistributedMemberFunctionExecution.java index 7dee2e54..95f96636 100644 --- a/src/main/java/org/springframework/data/gemfire/function/MembersFunctionExecution.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/DistributedMemberFunctionExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -10,41 +10,36 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; -import java.io.Serializable; +import org.springframework.util.Assert; import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; import com.gemstone.gemfire.cache.execute.FunctionService; -import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.distributed.DistributedMember; /** * @author David Turanski * */ -public class MembersFunctionExecution extends FunctionExecution { +public class DistributedMemberFunctionExecution extends FunctionExecution { - private final DistributedSystem distributedSystem; + private final DistributedMember distributedMember; /** - * @param functionId - * @param args + * + * @param distributedMember */ - public MembersFunctionExecution(DistributedSystem distributedSystem, Function function, Serializable... args) { - super(function, args); - this.distributedSystem = distributedSystem; + public DistributedMemberFunctionExecution(DistributedMember distributedMember) { + super(); + Assert.notNull(distributedMember); + this.distributedMember = distributedMember; } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.FunctionExecution#getExecution() - */ + @Override protected Execution getExecution() { - return FunctionService.onMembers(this.distributedSystem); + return FunctionService.onMember(this.distributedMember); } - - } diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/DistributedMembersFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/DistributedMembersFunctionExecution.java new file mode 100644 index 00000000..9a3f157a --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/DistributedMembersFunctionExecution.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.util.Set; + +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; +import com.gemstone.gemfire.distributed.DistributedMember; + +/** + * @author David Turanski + * + */ +public class DistributedMembersFunctionExecution extends FunctionExecution { + + private final Set distributedMembers; + /** + * + * @param distributedMembers + */ + public DistributedMembersFunctionExecution(Set distributedMembers ) { + super( ); + this.distributedMembers = distributedMembers; + } + + @Override + protected Execution getExecution() { + return FunctionService.onMembers(this.distributedMembers); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/FunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecution.java similarity index 61% rename from src/main/java/org/springframework/data/gemfire/function/FunctionExecution.java rename to src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecution.java index 71a06854..1b424fb1 100644 --- a/src/main/java/org/springframework/data/gemfire/function/FunctionExecution.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -10,10 +10,10 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; -import java.io.Serializable; -import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -25,40 +25,47 @@ import org.springframework.util.StringUtils; import com.gemstone.gemfire.cache.execute.Execution; import com.gemstone.gemfire.cache.execute.Function; import com.gemstone.gemfire.cache.execute.FunctionException; +import com.gemstone.gemfire.cache.execute.FunctionService; import com.gemstone.gemfire.cache.execute.ResultCollector; /** + * Base class for * Creating a GemFire {@link Execution} using {@link FunctionService} * @author David Turanski */ -public abstract class FunctionExecution { +public abstract class FunctionExecution { protected final Log logger = LogFactory.getLog(this.getClass()); private volatile ResultCollector collector; - private final Serializable[] args; + private Object[] args; private Function function; - private final String functionId; + private String functionId; private long timeout; - public FunctionExecution(Function function, Serializable... args) { + public FunctionExecution(Function function, Object... args) { Assert.notNull(function,"function cannot be null"); this.function = function; this.functionId = function.getId(); this.args = args; } - public FunctionExecution(String functionId, Serializable... args) { + public FunctionExecution(String functionId, Object... args) { Assert.isTrue(StringUtils.hasLength(functionId),"functionId cannot be null or empty"); this.functionId = functionId; this.args = args; } + protected FunctionExecution() { + + } + + public ResultCollector getCollector() { return collector; } - public Serializable[] getArgs() { + public Object[] getArgs() { return args; } @@ -74,9 +81,10 @@ public abstract class FunctionExecution { this.collector = collector; } + @SuppressWarnings("unchecked") - public List execute() { + public Iterable execute() { Execution execution = this.getExecution(); if (getKeys() != null) { execution = execution.withFilter(getKeys()); @@ -96,9 +104,11 @@ public abstract class FunctionExecution { resultsCollector = (ResultCollector) execution.execute(function); } + Iterable results = null; + if (this.timeout > 0 ){ try { - return (List)resultsCollector.getResult(this.timeout, TimeUnit.MILLISECONDS); + results= (Iterable)resultsCollector.getResult(this.timeout, TimeUnit.MILLISECONDS); } catch (FunctionException e) { throw new RuntimeException(e); @@ -107,27 +117,52 @@ public abstract class FunctionExecution { throw new RuntimeException(e); } } else { - return (List)resultsCollector.getResult(); + + results = (Iterable) resultsCollector.getResult(); } + + return replaceSingletonNullCollectionWithEmptyList(results); + } - public T executeAndExtract() { - return this.execute().get(0); + public T executeAndExtract() { + Iterable results = this.execute(); + if (results == null || !results.iterator().hasNext()) { + return null; + } + + return results.iterator().next(); } protected abstract Execution getExecution(); + protected FunctionExecution setFunctionId(String functionId) { + this.functionId = functionId; + return this; + } + + protected FunctionExecution setFunction(Function function) { + this.function = function; + return this; + } + + protected FunctionExecution setArgs(Object... args) { + this.args = args; + return this; + } + protected Set getKeys() { return null; } - public void setTimeout(long timeout) { + public FunctionExecution setTimeout(long timeout) { this.timeout = timeout; + return this; } public long getTimeout() { return timeout; - } + } /** * @return @@ -135,5 +170,23 @@ public abstract class FunctionExecution { private boolean isRegisteredFunction() { return function == null; } + + private Iterable replaceSingletonNullCollectionWithEmptyList(Iterable results) { + if (results == null) { + return results; + } + Iterator it = results.iterator(); + + if (!it.hasNext()) { + return results; + } + + if (it.next()==null && !it.hasNext()) { + return new ArrayList(); + } + + return results; + + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecutionMethodMetadata.java b/src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecutionMethodMetadata.java new file mode 100644 index 00000000..204aa485 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/FunctionExecutionMethodMetadata.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * Base class for method level metadata for a function execution interface. This is used at runtime by the + * function execution proxy to create the corresponding Gemfire function {@link Execution} + * + * @author David Turanski + * + */ +abstract class FunctionExecutionMethodMetadata { + + protected final Map methodMetadata = new HashMap(); + private final boolean singletonInterface; + + public FunctionExecutionMethodMetadata(final Class serviceInterface) { + + this.singletonInterface = serviceInterface.getMethods().length == 1; + + ReflectionUtils.doWithMethods(serviceInterface, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + T mmd = newMetadataInstance(method); + if (mmd.getFunctionId() == null) { + mmd.setFunctionId(serviceInterface.getName() + "." + method.getName()); + } + + methodMetadata.put(method, mmd); + } + }); + } + + protected abstract T newMetadataInstance(Method method); + + T getMethodMetadata(Method method) { + return methodMetadata.get(method); + } + + boolean isSingletonInterface() { + return this.singletonInterface; + } + + T getSingletonMethodMetada() { + Assert.isTrue(isSingletonInterface(),"this is not a singleton interface."); + return methodMetadata.values().iterator().next(); + } +} + + +class MethodMetadata { + + private String functionId; + + public MethodMetadata(Method method) { + String annotatedFunctionId = annotatedFunctionId(method); + this.functionId = (annotatedFunctionId == null) ? null : annotatedFunctionId; + } + + /** + * @return the functionId + */ + public String getFunctionId() { + return functionId; + } + + public void setFunctionId(String functionId) { + this.functionId = functionId; + } + + private String annotatedFunctionId(Method method) { + FunctionId functionIdAnnotation = method.getAnnotation(FunctionId.class); + return (functionIdAnnotation == null) ? null : functionIdAnnotation.value(); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionCallback.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionCallback.java similarity index 82% rename from src/main/java/org/springframework/data/gemfire/function/GemfireFunctionCallback.java rename to src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionCallback.java index 81ea3365..e7ad8cd8 100644 --- a/src/main/java/org/springframework/data/gemfire/function/GemfireFunctionCallback.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionCallback.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -10,11 +10,12 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; import com.gemstone.gemfire.cache.execute.Execution; /** + * A callback for Gemfire Function Templates * @author David Turanski * */ diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java new file mode 100644 index 00000000..13267154 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionOperations.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2012 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.function.execution; + + +import com.gemstone.gemfire.cache.execute.Function; + +/** + * + * An interface for invoking Gemfire functions + * + * @author David Turanski + * + * @param the preferred return type + */ +public interface GemfireFunctionOperations { + + /** + * Execute an unregistered function + * @param function the function + * @param args calling arguments + * @return the contents of the results collector + */ + public abstract Iterable execute(Function function, Object... args); + + /** + * Execute an unregistered function with an expected singleton result + * @param function the function + * @param args calling arguments + * @return the first item in the results collector + */ + public abstract T executeAndExtract(Function function, Object... args); + + /** + * Execute a function registered with an ID + * @param functionId the function ID + * @param args the calling arguments + * @return the results + */ + public abstract Iterable execute(String functionId, Object... args); + + /** + * Execute a function registered with an ID and with an expected singleton result + * @param functionId the function ID + * @param args the calling arguments + * @return the first item in the results collector + */ + public abstract T executeAndExtract(String functionId, Object... args); + + + /** + * Execute a function using a native GemFire {@link Execution} instance + * @param callback a callback providing the execution instance + * @return the execution result + */ + public abstract T execute(GemfireFunctionCallback callback); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBean.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBean.java new file mode 100644 index 00000000..ebf7b307 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBean.java @@ -0,0 +1,178 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.lang.reflect.Method; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import com.gemstone.gemfire.cache.execute.FunctionException; + +/** + * A proxy Factory Bean for all non-region function execution interfaces + * + * @author David Turanski + * + */ +public class GemfireFunctionProxyFactoryBean implements FactoryBean, MethodInterceptor, BeanClassLoaderAware, InitializingBean { + + protected volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + protected final Class serviceInterface; + + protected volatile Object serviceProxy; + + private volatile boolean initialized; + + protected String functionId; + + protected Log logger = LogFactory.getLog(this.getClass()); + + protected final GemfireFunctionOperations gemfireFunctionOperations; + + private FunctionExecutionMethodMetadata methodMetadata; + + /** + * @param serviceInterface the proxied interface + * @param functionId the associated function id (must be a function registered by this id with the GemFire {@link FunctionService} + * @param gemfireFunctionOperations an interface used to delegate the function invocation (typically a GemFire function template) + */ + public GemfireFunctionProxyFactoryBean(Class serviceInterface, + GemfireFunctionOperations gemfireFunctionOperations) { + Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); + Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); + this.serviceInterface = serviceInterface; + this.gemfireFunctionOperations = gemfireFunctionOperations; + this.methodMetadata = new DefaultFunctionExecutionMethodMetadata(serviceInterface); + } + + + + protected Iterable invokeFunction(Method method, Object[] args) { + MethodMetadata mmd = this.methodMetadata.getMethodMetadata(method); + return this.gemfireFunctionOperations.execute(mmd.getFunctionId(), args); + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + beanClassLoader = classLoader; + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + + if (AopUtils.isToStringMethod(invocation.getMethod())) { + return "Gemfire function proxy for service interface [" + this.serviceInterface + "]"; + } + + if (logger.isDebugEnabled()) { + logger.debug("invoking method " + invocation.getMethod().getName()); + } + + Iterable results = invokeFunction(invocation.getMethod(), invocation.getArguments()); + + return extractResult(results, invocation.getMethod().getReturnType()); + } + + + @Override + public Object getObject() throws Exception { + if (this.serviceProxy == null) { + this.onInit(); + Assert.notNull(this.serviceProxy, "failed to initialize proxy"); + } + return this.serviceProxy; + } + + @Override + public Class getObjectType() { + return (this.serviceInterface != null ? this.serviceInterface : null); + } + + @Override + public boolean isSingleton() { + return true; + } + + protected void onInit() { + if (this.initialized) { + return; + } + ProxyFactory proxyFactory = new ProxyFactory(serviceInterface, this); + this.serviceProxy = proxyFactory.getProxy(this.beanClassLoader); + this.initialized = true; + } + + protected String annotatedFunctionId(Method method) { + FunctionId functionIdAnnotation = method.getAnnotation(FunctionId.class); + return (functionIdAnnotation == null) ? null: functionIdAnnotation.value(); + } + + + /** + * Optional to set a default function Id for a single method interface with no {code}@FunctionId{code} annotations + * @param functionId + */ + protected void setFunctionId(String functionId) { + this.functionId = functionId; + } + + /* + * Match the result to the declared return type + */ + private Object extractResult(Iterable results, Class returnType) { + Object result = null; + if (results != null) { + if (Iterable.class.isAssignableFrom(returnType)) { + result = results; + } else { + int nonNullItems = 0; + for (Object obj : results) { + if (obj != null) { + if (++nonNullItems > 1) { + throw new FunctionException("multiple results found for single valued return type"); + } else { + result = obj; + } + } + } + } + if (logger.isDebugEnabled()) { + logger.debug("returning result as " + result.getClass().getName()); + } + } + return result; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception { + if (this.functionId != null) { + Assert.isTrue(this.methodMetadata.isSingletonInterface(), "cannot assign default function id if interface has multiple methods"); + this.methodMetadata.getSingletonMethodMetada().setFunctionId(this.functionId); + } + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java new file mode 100644 index 00000000..a54ab0b5 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMemberFunctionTemplate.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2012 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.function.execution; + + +import com.gemstone.gemfire.distributed.DistributedMember; + +/** + * + * @author David Turanski + * + */ +public class GemfireOnMemberFunctionTemplate extends AbstractFunctionTemplate { + + private final DistributedMember distributedMember; + private final String[] groups; + + public GemfireOnMemberFunctionTemplate (DistributedMember distributedMember) { + this.distributedMember = distributedMember; + this.groups = null; + } + + public GemfireOnMemberFunctionTemplate (String[] groups) { + this.distributedMember = null; + this.groups = groups; + } + + public GemfireOnMemberFunctionTemplate () { + this.distributedMember = null; + this.groups = null; + } + + + protected FunctionExecution getFunctionExecution() { + if (distributedMember == null && groups == null) { + return new DefaultMemberFunctionExecution(); + } else if (distributedMember == null) { + return new GroupMemberFunctionExecution(this.groups); + + } + return new DistributedMemberFunctionExecution(this.distributedMember); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMembersFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMembersFunctionTemplate.java new file mode 100644 index 00000000..ed64bad6 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnMembersFunctionTemplate.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.util.Set; + + +import com.gemstone.gemfire.distributed.DistributedMember; + +/** + * @author David Turanski + * + */ +public class GemfireOnMembersFunctionTemplate extends AbstractFunctionTemplate { + + private final Set distributedMembers; + private final String[] groups; + + GemfireOnMembersFunctionTemplate (Set distributedMembers) { + this.distributedMembers = distributedMembers; + this.groups = null; + } + + GemfireOnMembersFunctionTemplate (String[] groups) { + this.distributedMembers = null; + this.groups = groups; + } + + GemfireOnMembersFunctionTemplate () { + this.distributedMembers = null; + this.groups = null; + } + + + protected FunctionExecution getFunctionExecution() { + if (distributedMembers == null && groups == null) { + return new AllMembersFunctionExecution(); + } else if (distributedMembers == null) { + return new GroupMembersFunctionExecution(this.groups); + + } + return new DistributedMembersFunctionExecution(this.distributedMembers); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java new file mode 100644 index 00000000..18800d38 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionFunctionTemplate.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.util.Set; + +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.execute.Function; + +/** + * @author David Turanski + * + */ +public class GemfireOnRegionFunctionTemplate extends AbstractFunctionTemplate implements GemfireOnRegionOperations { + + private Region region; + + /** + * + * @param region + */ + public GemfireOnRegionFunctionTemplate(Region region) { + Assert.notNull(region, "Region cannot be null"); + this.region = region; + } + + + @Override + public Iterable execute(Function function, Set keys, Object... args) { + return execute(new RegionFunctionExecution(region) + .setKeys(keys) + .setFunction(function) + .setTimeout(timeout) + .setArgs(args) ); + } + + + @Override + public Iterable execute(String functionId, Set keys, Object... args) { + return execute(new RegionFunctionExecution(region) + .setKeys(keys) + .setFunctionId(functionId) + .setTimeout(timeout) + .setArgs(args) ); + } + + @Override + public T executeAndextract(String functionId, Set keys, Object... args) { + return executeAndExtract(new RegionFunctionExecution(region) + .setKeys(keys) + .setFunctionId(functionId) + .setTimeout(timeout) + .setArgs(args) ); + } + + @Override + protected FunctionExecution getFunctionExecution() { + return new RegionFunctionExecution(this.region); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java new file mode 100644 index 00000000..bce4f250 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnRegionOperations.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.util.Set; + +import com.gemstone.gemfire.cache.execute.Function; + +/** + * @author David Turanski + * + * @param + */ +public interface GemfireOnRegionOperations extends GemfireFunctionOperations { + + public abstract Iterable execute(String functionId, Set keys, Object... args); + public abstract Iterable execute(Function function, Set keys, Object... args); + public abstract T executeAndextract(String functionId, Set keys, Object... args); + +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServerFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServerFunctionTemplate.java new file mode 100644 index 00000000..c02d4f0c --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServerFunctionTemplate.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 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.function.execution; + + +import com.gemstone.gemfire.cache.RegionService; +import com.gemstone.gemfire.cache.client.Pool; + +/** + * @author David Turanski + * + */ +public class GemfireOnServerFunctionTemplate extends AbstractFunctionTemplate { + + private final RegionService cache; + private final Pool pool; + + + GemfireOnServerFunctionTemplate (RegionService cache) { + this.cache = cache; + this.pool = null; + } + + GemfireOnServerFunctionTemplate (Pool pool) { + this.pool = pool; + this.cache = null; + } + + @Override + protected FunctionExecution getFunctionExecution() { + if (this.pool == null) { + return new ServerFunctionExecution(this.cache); + } + return new PoolServerFunctionExecution(this.pool); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServersFunctionTemplate.java b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServersFunctionTemplate.java new file mode 100644 index 00000000..fe519d88 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GemfireOnServersFunctionTemplate.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2012 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.function.execution; + + +import com.gemstone.gemfire.cache.RegionService; +import com.gemstone.gemfire.cache.client.Pool; + +/** + * @author David Turanski + * + */ +public class GemfireOnServersFunctionTemplate extends AbstractFunctionTemplate { + + private final RegionService cache; + private final Pool pool; + + + GemfireOnServersFunctionTemplate (RegionService cache) { + this.cache = cache; + this.pool = null; + } + + GemfireOnServersFunctionTemplate (Pool pool) { + this.pool = pool; + this.cache = null; + } + + @Override + protected FunctionExecution getFunctionExecution() { + if (this.pool == null) { + return new ServersFunctionExecution(this.cache); + } + return new PoolServersFunctionExecution(this.pool); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GroupMemberFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/GroupMemberFunctionExecution.java new file mode 100644 index 00000000..99a6c5ee --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GroupMemberFunctionExecution.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * @author David Turanski + * + */ +public class GroupMemberFunctionExecution extends FunctionExecution { + + private final String groups[]; + + /** + * + * @param groups + */ + public GroupMemberFunctionExecution(String... groups) { + super(); + Assert.notEmpty(groups, "groups cannot be null or empty."); + this.groups = groups; + } + + @Override + protected Execution getExecution() { + return FunctionService.onMember(this.groups); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/GroupMembersFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/GroupMembersFunctionExecution.java new file mode 100644 index 00000000..ebba718f --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/GroupMembersFunctionExecution.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * @author David Turanski + * + */ +public class GroupMembersFunctionExecution extends FunctionExecution { + + private final String groups[]; + + /** + * + * @param groups + */ + public GroupMembersFunctionExecution(String... groups) { + super(); + Assert.notEmpty(groups, "groups cannot be null or empty."); + this.groups = groups; + } + + @Override + protected Execution getExecution() { + return FunctionService.onMember(this.groups); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionExecutionMethodMetadata.java b/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionExecutionMethodMetadata.java new file mode 100644 index 00000000..590bc30b --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionExecutionMethodMetadata.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import java.lang.reflect.Method; +import java.util.Set; + +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.GemfireFunctionUtils; + + + +/** + * @author David Turanski + * + */ +class OnRegionExecutionMethodMetadata extends FunctionExecutionMethodMetadata { + + /** + * @param serviceInterface + */ + public OnRegionExecutionMethodMetadata(Class serviceInterface) { + super(serviceInterface); + } + + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.FunctionExecutionMethodMetadata#newMetadataInstance(java.lang.reflect.Method) + */ + @Override + protected OnRegionMethodMetadata newMetadataInstance(Method method) { + return new OnRegionMethodMetadata(method); + } + +} + +class OnRegionMethodMetadata extends MethodMetadata { + + private final int filterArgPosition; + + public OnRegionMethodMetadata(Method method) { + super(method); + this.filterArgPosition = GemfireFunctionUtils.getAnnotationParameterPosition(method, Filter.class, new Class[]{Set.class}); + } + + public int getFilterArgPosition() { + return this.filterArgPosition; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionFunctionProxyFactoryBean.java b/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionFunctionProxyFactoryBean.java new file mode 100644 index 00000000..97a9c32c --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/OnRegionFunctionProxyFactoryBean.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2012 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.function.execution; + + +import java.lang.reflect.Method; +import java.util.Set; + +import org.springframework.data.gemfire.util.ArrayUtils; + +/** + * @author David Turanski + * + */ +public class OnRegionFunctionProxyFactoryBean extends GemfireFunctionProxyFactoryBean { + private OnRegionExecutionMethodMetadata methodMetadata; + /** + * @param serviceInterface + * @param gemfireOnRegionOperations an {@link GemfireOnRegionOperations} instance + */ + public OnRegionFunctionProxyFactoryBean(Class serviceInterface, + GemfireOnRegionOperations gemfireOnRegionOperations) { + super(serviceInterface, (GemfireFunctionOperations) gemfireOnRegionOperations); + methodMetadata = new OnRegionExecutionMethodMetadata(serviceInterface); + } + + @Override + protected Iterable invokeFunction(Method method, Object[] args) { + + Set filter = null; + + Iterable results = null; + + GemfireOnRegionOperations gemfireOnRegionOperations = (GemfireOnRegionOperations) this.gemfireFunctionOperations; + + OnRegionMethodMetadata ormmd = methodMetadata.getMethodMetadata(method); + + int filterArgPosition = ormmd.getFilterArgPosition(); + + String functionId = ormmd.getFunctionId(); + + /* + * extract filter from args if necessary + */ + if (filterArgPosition >=0 ) { + filter = (Set)args[filterArgPosition]; + args = ArrayUtils.remove(args, filterArgPosition); + } + + if (filter == null) { + results = gemfireOnRegionOperations.execute(functionId, args); + } else { + results = gemfireOnRegionOperations.execute(functionId, filter, args); + } + + return results; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/PoolServerFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/PoolServerFunctionExecution.java new file mode 100644 index 00000000..90fd5151 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/PoolServerFunctionExecution.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.Pool; +import com.gemstone.gemfire.cache.client.PoolManager; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * Creates a GemFire {@link Execution} using {code}FunctionService.onServer(Pool pool){code} + * @author David Turanski + * + */ +public class PoolServerFunctionExecution extends FunctionExecution implements InitializingBean { + + + private Pool pool; + private String poolname; + + + /** + * @param pool the {@link Pool} + */ + public PoolServerFunctionExecution(Pool pool) { + super(); + Assert.notNull(pool, "pool cannot be null"); + this.pool = pool; + } + + public PoolServerFunctionExecution(String poolname) { + super(); + Assert.notNull(poolname, "pool name cannot be null"); + this.poolname = poolname; + + } + + + @Override + protected Execution getExecution() { + return FunctionService.onServer(this.pool); + } + + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception { + this.pool = PoolManager.find(poolname); + Assert.notNull(pool," pool " + poolname+ " does not exist"); + + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/PoolServersFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/PoolServersFunctionExecution.java new file mode 100644 index 00000000..cc987a72 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/PoolServersFunctionExecution.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.client.Pool; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * Creates a GemFire {@link Execution} using {code}FunctionService.onServers(Pool pool){code} + * @author David Turanski + * + */ +public class PoolServersFunctionExecution extends FunctionExecution { + + + private final Pool pool; + + /** + * @param pool the {@link Pool} + */ + public PoolServersFunctionExecution(Pool pool ) { + super(); + Assert.notNull(pool, "pool cannot be null"); + this.pool = pool; + } + + @Override + protected Execution getExecution() { + return FunctionService.onServers(this.pool); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/RegionFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/RegionFunctionExecution.java similarity index 66% rename from src/main/java/org/springframework/data/gemfire/function/RegionFunctionExecution.java rename to src/main/java/org/springframework/data/gemfire/function/execution/RegionFunctionExecution.java index 9dc8b4e2..0fa86ef9 100644 --- a/src/main/java/org/springframework/data/gemfire/function/RegionFunctionExecution.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/RegionFunctionExecution.java @@ -10,38 +10,35 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; -import java.io.Serializable; import java.util.Set; +import org.springframework.util.CollectionUtils; + import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; import com.gemstone.gemfire.cache.execute.FunctionService; - + /** + * Creates a GemFire {@link Execution} using {code}FunctionService.onRegion(Region region){code} * @author David Turanski * */ -public class RegionFunctionExecution extends FunctionExecution { +public class RegionFunctionExecution extends FunctionExecution { private final Region region; private volatile Set keys; - public RegionFunctionExecution(Region region, Function function, Serializable... args) { - super(function, args); + public RegionFunctionExecution(Region region) { + super(); this.region = region; } - public RegionFunctionExecution(Region region, String functionId, Serializable... args) { - super(functionId, args); - this.region = region; - } - - public void setKeys(Set keys) { + public RegionFunctionExecution setKeys(Set keys) { this.keys = keys; + return this; } protected Set getKeys() { @@ -53,6 +50,10 @@ public class RegionFunctionExecution extends FunctionExecution { */ @Override protected Execution getExecution() { - return FunctionService.onRegion(region); + Execution execution = FunctionService.onRegion(region); + if (!CollectionUtils.isEmpty(this.keys) ) { + execution = execution.withFilter(keys); + } + return execution; } } diff --git a/src/main/java/org/springframework/data/gemfire/function/execution/ServerFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/ServerFunctionExecution.java new file mode 100644 index 00000000..4ef8d4b5 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/function/execution/ServerFunctionExecution.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import org.springframework.util.Assert; + +import com.gemstone.gemfire.cache.RegionService; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionService; + +/** + * Creates a GemFire {@link Execution} using {code}FunctionService.onServer(RegionService regionService){code} + * @author David Turanski + * + */ +public class ServerFunctionExecution extends FunctionExecution { + + + private RegionService regionService; + + + public ServerFunctionExecution(RegionService regionService) { + super(); + Assert.notNull(regionService,"regionService cannot be null"); + this.regionService = regionService; + } + + + @Override + protected Execution getExecution() { + return FunctionService.onServer(this.regionService); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/function/ServersFunctionExecution.java b/src/main/java/org/springframework/data/gemfire/function/execution/ServersFunctionExecution.java similarity index 57% rename from src/main/java/org/springframework/data/gemfire/function/ServersFunctionExecution.java rename to src/main/java/org/springframework/data/gemfire/function/execution/ServersFunctionExecution.java index 351f7b67..cbfafe5f 100644 --- a/src/main/java/org/springframework/data/gemfire/function/ServersFunctionExecution.java +++ b/src/main/java/org/springframework/data/gemfire/function/execution/ServersFunctionExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 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 @@ -10,20 +10,20 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; -import java.io.Serializable; +import org.springframework.util.Assert; import com.gemstone.gemfire.cache.RegionService; import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.Function; import com.gemstone.gemfire.cache.execute.FunctionService; /** + * Creates a GemFire {@link Execution} using {code}FunctionService.onServers(RegionService regionService){code} * @author David Turanski * */ -public class ServersFunctionExecution extends FunctionExecution { +public class ServersFunctionExecution extends FunctionExecution { private final RegionService regionService; @@ -34,25 +34,12 @@ public class ServersFunctionExecution extends FunctionExecution { * @param function * @param args */ - public ServersFunctionExecution(RegionService regionService, Function function, Serializable... args) { - super(function, args); - this.regionService = regionService; - } - - /** - * - * @param regionService e.g., Cache,Client, or GemFireCache - * @param functionId - * @param args - */ - public ServersFunctionExecution(RegionService regionService, String functionId, Serializable... args) { - super(functionId, args); + public ServersFunctionExecution(RegionService regionService ) { + super(); + Assert.notNull(regionService,"regionService cannot be null"); this.regionService = regionService; } - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.FunctionExecution#getExecution() - */ @Override protected Execution getExecution() { return FunctionService.onServers(this.regionService); diff --git a/src/main/java/org/springframework/data/gemfire/serialization/AsmInstantiatorGenerator.java b/src/main/java/org/springframework/data/gemfire/serialization/AsmInstantiatorGenerator.java index 4530ad92..bead5ce9 100644 --- a/src/main/java/org/springframework/data/gemfire/serialization/AsmInstantiatorGenerator.java +++ b/src/main/java/org/springframework/data/gemfire/serialization/AsmInstantiatorGenerator.java @@ -176,7 +176,7 @@ public class AsmInstantiatorGenerator implements InstantiatorGenerator, Opcodes } byte[] generateClassBytecode(String className, Class clazz, int classId) { - ClassWriter cw = new ClassWriter(false); + ClassWriter cw = new ClassWriter(0); cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, null, INSTANTIATOR_NAME, new String[] { SERIALIZABLE_NAME }); FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, CLASS_FIELD_NAME, CLASS_DESCRIPTOR, null, diff --git a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java new file mode 100644 index 00000000..eaffae4c --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2012 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.util; + +/** + * @author David Turanski + * + */ + + +public abstract class ArrayUtils { + + /** + * Insert an element into an array. The element is inserted at the + * given position, all elements afterwards are moved to the right. + * + * @param originalArray array to insert into + * @param pos position at which to insert the element + * @param element element to add + * @return the new array + */ + public static Object[] insert(Object[] originalArray, int pos, Object element) { + Object[] newArray = (Object[]) java.lang.reflect.Array.newInstance( + originalArray.getClass().getComponentType(), originalArray.length + 1); + + + // copy everything before the given position + if (pos > 0) { + System.arraycopy(originalArray, 0, newArray, 0, pos); // does not copy originalArray[pos], where we insert + } + + // insert + newArray[pos] = element; + + // copy remaining elements + if (pos < originalArray.length) { + System.arraycopy(originalArray, pos, // originalArray[pos] first element copied + newArray, pos + 1, // newArray[pos + 1] first destination + originalArray.length - pos); // number of elements left + } + + + return newArray; + } + + /** + * Remove element from an array. The element is removed at the + * specified position, and all remaining elements are moved to the left. + * + * @param originalArray array to remove from + * @param pos position to remove + * @return the new array + */ + public static Object[] remove(Object[] originalArray, int pos) { + Object[] newArray = (Object[])java.lang.reflect.Array.newInstance( + originalArray.getClass().getComponentType(), originalArray.length - 1); + + + + // Copy everything before + if (pos > 0) { + System.arraycopy(originalArray, 0, newArray, 0, pos); // originalArray[pos - 1] is last element copied + } + + + // Copy everything after + if (pos < originalArray.length - 1) { + System.arraycopy(originalArray, pos + 1, // originalArray[pos + 1] is first element copied + newArray, pos, // first position to copy into + originalArray.length - 1 - pos); + } + + + return newArray; + } + + +} diff --git a/src/main/java/org/springframework/data/gemfire/wan/AbstractWANComponentFactoryBean.java b/src/main/java/org/springframework/data/gemfire/wan/AbstractWANComponentFactoryBean.java index 9c3c3802..fbea4c96 100644 --- a/src/main/java/org/springframework/data/gemfire/wan/AbstractWANComponentFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/wan/AbstractWANComponentFactoryBean.java @@ -34,15 +34,25 @@ public abstract class AbstractWANComponentFactoryBean implements FactoryBean< DisposableBean { protected Log log = LogFactory.getLog(this.getClass()); - protected String name; + private String name; protected final Cache cache; protected Object factory; + private String beanName; + protected AbstractWANComponentFactoryBean(Cache cache) { this.cache = cache; } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name!=null ? name: beanName; + } @Override public void destroy() throws Exception { @@ -50,13 +60,13 @@ public abstract class AbstractWANComponentFactoryBean implements FactoryBean< } @Override - public final void setBeanName(String name) { - this.name = name; + public final void setBeanName(String beanName) { + this.beanName = beanName; } @Override public final void afterPropertiesSet() throws Exception { - Assert.notNull(name, "Name cannot be null"); + Assert.notNull(getName(), "Name cannot be null"); Assert.notNull(cache, "Cache cannot be null"); doInit(); } diff --git a/src/main/java/org/springframework/data/gemfire/wan/AsyncEventQueueFactoryBean.java b/src/main/java/org/springframework/data/gemfire/wan/AsyncEventQueueFactoryBean.java index 255b2381..1a6196c2 100644 --- a/src/main/java/org/springframework/data/gemfire/wan/AsyncEventQueueFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/wan/AsyncEventQueueFactoryBean.java @@ -92,7 +92,7 @@ public class AsyncEventQueueFactoryBean extends AbstractWANComponentFactoryBean< asyncEventQueueFactory.setMaximumQueueMemory(maximumQueueMemory); } - asyncEventQueue = asyncEventQueueFactory.create(name, asyncEventListener); + asyncEventQueue = asyncEventQueueFactory.create(getName(), asyncEventListener); } @Override diff --git a/src/main/java/org/springframework/data/gemfire/wan/GatewayHubFactoryBean.java b/src/main/java/org/springframework/data/gemfire/wan/GatewayHubFactoryBean.java index ad914526..91515ff3 100644 --- a/src/main/java/org/springframework/data/gemfire/wan/GatewayHubFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/wan/GatewayHubFactoryBean.java @@ -76,6 +76,7 @@ public class GatewayHubFactoryBean extends AbstractWANComponentFactoryBean { +public class GatewaySenderFactoryBean extends AbstractWANComponentFactoryBean { private static List validOrderPolicyValues = Arrays.asList("KEY", "PARTITION", "THREAD"); private GatewaySender gatewaySender; @@ -58,7 +58,7 @@ public class GatewaySenderFactoryBean extends AbstractWANComponentFactoryBean getObjectType() { - return GatewaySender.class; + return SmartLifecycleGatewaySender.class; } @Override @@ -151,9 +151,9 @@ public class GatewaySenderFactoryBean extends AbstractWANComponentFactoryBean getGatewayEventFilters() { + return this.delegate.getGatewayEventFilters(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getGatewayTransportFilters() + */ + @Override + public List getGatewayTransportFilters() { + return this.delegate.getGatewayTransportFilters(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getId() + */ + @Override + public String getId() { + return this.delegate.getId(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getMaximumQueueMemory() + */ + @Override + public int getMaximumQueueMemory() { + return this.delegate.getMaximumQueueMemory(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getOrderPolicy() + */ + @Override + public OrderPolicy getOrderPolicy() { + return this.delegate.getOrderPolicy(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getRemoteDSId() + */ + @Override + public int getRemoteDSId() { + return this.delegate.getRemoteDSId(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getSocketBufferSize() + */ + @Override + public int getSocketBufferSize() { + return this.delegate.getSocketBufferSize(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#getSocketReadTimeout() + */ + @Override + public int getSocketReadTimeout() { + return this.delegate.getSocketReadTimeout(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isBatchConflationEnabled() + */ + @Override + public boolean isBatchConflationEnabled() { + return this.delegate.isBatchConflationEnabled(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isDiskSynchronous() + */ + @Override + public boolean isDiskSynchronous() { + return this.delegate.isDiskSynchronous(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isManualStart() + */ + @Override + public boolean isManualStart() { + return true; + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isParallel() + */ + @Override + public boolean isParallel() { + return this.delegate.isParallel(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isPaused() + */ + @Override + public boolean isPaused() { + return this.delegate.isPaused(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isPersistenceEnabled() + */ + @Override + public boolean isPersistenceEnabled() { + return this.delegate.isPersistenceEnabled(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#isRunning() + */ + @Override + public boolean isRunning() { + return this.delegate.isRunning(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#pause() + */ + @Override + public void pause() { + this.delegate.pause(); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#removeGatewayEventFilter(com.gemstone.gemfire.cache.wan.GatewayEventFilter) + */ + @Override + public void removeGatewayEventFilter(GatewayEventFilter eventFilter) { + this.delegate.removeGatewayEventFilter(eventFilter); + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#resume() + */ + @Override + public void resume() { + this.delegate.resume(); + + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#start() + */ + @Override + public void start() { + this.delegate.start(); + + } + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.wan.GatewaySender#stop() + */ + @Override + public void stop() { + this.delegate.stop(); + } + + /* (non-Javadoc) + * @see org.springframework.context.Phased#getPhase() + */ + @Override + public int getPhase() { + return Integer.MAX_VALUE; + } + + /* (non-Javadoc) + * @see org.springframework.context.SmartLifecycle#isAutoStartup() + */ + @Override + public boolean isAutoStartup() { + return this.autoStartup ; + } + + /* (non-Javadoc) + * @see org.springframework.context.SmartLifecycle#stop(java.lang.Runnable) + */ + @Override + public void stop(Runnable callback) { + stop(); + callback.run(); + } + +} diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.3.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.3.xsd index b46e860c..2de60eaa 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.3.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-data-gemfire-1.3.xsd @@ -2,15 +2,20 @@ - - + + + @@ -26,6 +31,32 @@ targetNamespace="http://www.springframework.org/schema/data/gemfire" elementForm + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.3.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.3.xsd index c014672f..06ec47bb 100755 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.3.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.3.xsd @@ -2250,6 +2250,13 @@ Inner bean definition of the event filter minOccurs="0" maxOccurs="1" /> + + + + + @@ -2497,6 +2504,13 @@ use inner bean declarations. + + + + + diff --git a/src/test/java/org/springframework/data/gemfire/ForkUtil.java b/src/test/java/org/springframework/data/gemfire/ForkUtil.java index bf09ab22..4ab4f224 100644 --- a/src/test/java/org/springframework/data/gemfire/ForkUtil.java +++ b/src/test/java/org/springframework/data/gemfire/ForkUtil.java @@ -32,8 +32,10 @@ import java.util.concurrent.atomic.AtomicBoolean; public class ForkUtil { private static OutputStream os; private static String TEMP_DIR = System.getProperty("java.io.tmpdir"); + + - public static OutputStream cloneJVM(String argument) { + public static OutputStream cloneJVM(String arguments) { String cp = System.getProperty("java.class.path"); String home = System.getProperty("java.home"); @@ -41,9 +43,9 @@ public class ForkUtil { String sp = System.getProperty("file.separator"); String java = home + sp + "bin" + sp + "java"; String argCp = " -cp " + cp; - String argClass = argument; + - String cmd = java + argCp + " " + argClass; + String cmd = java + argCp + " " + arguments; try { //ProcessBuilder builder = new ProcessBuilder(cmd, argCp, argClass); //builder.redirectErrorStream(true); @@ -107,12 +109,15 @@ public class ForkUtil { return startCacheServer("org.springframework.data.gemfire.fork.CacheServerProcess"); } - private static OutputStream startCacheServer(String className) { + public static OutputStream startCacheServer(String args) { + String className = args.split(" ")[0]; + + System.out.println("main class:" + className); if (controlFileExists(className)) { deleteControlFile(className); } - OutputStream os = cloneJVM(className); + OutputStream os = cloneJVM(args); int maxTime = 30000; int time = 0; while (!controlFileExists(className) && time < maxTime) { diff --git a/src/test/java/org/springframework/data/gemfire/RecreatingContextTest.java b/src/test/java/org/springframework/data/gemfire/RecreatingContextTest.java index 1f224d3e..2082ecd0 100644 --- a/src/test/java/org/springframework/data/gemfire/RecreatingContextTest.java +++ b/src/test/java/org/springframework/data/gemfire/RecreatingContextTest.java @@ -18,7 +18,6 @@ package org.springframework.data.gemfire; import org.junit.After; import org.junit.Before; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; /** diff --git a/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java index 230131a7..0ec0825a 100644 --- a/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.net.InetSocketAddress; import java.util.Collection; import java.util.Iterator; @@ -28,7 +29,6 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.gemfire.TestUtils; -import org.springframework.data.gemfire.client.PoolConnection; import org.springframework.data.gemfire.client.PoolFactoryBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -41,7 +41,7 @@ import com.gemstone.gemfire.cache.client.PoolManager; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("pool-ns.xml") public class PoolNamespaceTest { - + @Autowired private ApplicationContext context; @@ -58,10 +58,10 @@ public class PoolNamespaceTest { assertEquals(context.getBean("gemfirePool"), PoolManager.find("gemfirePool")); PoolFactoryBean pfb = (PoolFactoryBean) context.getBean("&gemfirePool"); - Collection locators = TestUtils.readField("locators", pfb); + Collection locators = TestUtils.readField("locators", pfb); assertEquals(1, locators.size()); - PoolConnection locator = locators.iterator().next(); - assertEquals("localhost", locator.getHost()); + InetSocketAddress locator = locators.iterator().next(); + assertEquals("localhost", locator.getHostName()); assertEquals(40403, locator.getPort()); } @@ -75,15 +75,15 @@ public class PoolNamespaceTest { assertFalse((Boolean) TestUtils.readField("multiUserAuthentication", pfb)); assertTrue((Boolean) TestUtils.readField("prSingleHopEnabled", pfb)); - Collection servers = TestUtils.readField("servers", pfb); + Collection servers = TestUtils.readField("servers", pfb); assertEquals(2, servers.size()); - Iterator iterator = servers.iterator(); - PoolConnection server = iterator.next(); - assertEquals("localhost", server.getHost()); + Iterator iterator = servers.iterator(); + InetSocketAddress server = iterator.next(); + assertEquals("localhost", server.getHostName()); assertEquals(40404, server.getPort()); server = iterator.next(); - assertEquals("localhost", server.getHost()); + assertEquals("localhost", server.getHostName()); assertEquals(40405, server.getPort()); } } diff --git a/src/test/java/org/springframework/data/gemfire/fork/CacheServerProcess.java b/src/test/java/org/springframework/data/gemfire/fork/CacheServerProcess.java index 3f5bfbc7..587d6827 100644 --- a/src/test/java/org/springframework/data/gemfire/fork/CacheServerProcess.java +++ b/src/test/java/org/springframework/data/gemfire/fork/CacheServerProcess.java @@ -28,6 +28,7 @@ import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheFactory; import com.gemstone.gemfire.cache.DataPolicy; import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionFactory; import com.gemstone.gemfire.cache.Scope; import com.gemstone.gemfire.cache.server.CacheServer; import com.gemstone.gemfire.distributed.DistributedSystem; @@ -43,21 +44,19 @@ public class CacheServerProcess { props.setProperty("name", "CqServer"); props.setProperty("log-level", "warning"); - System.out.println("\nConnecting to the distributed system and creating the cache."); - DistributedSystem ds = DistributedSystem.connect(props); - Cache cache = CacheFactory.create(ds); + Cache cache = new CacheFactory(props).create(); // Create region. - AttributesFactory factory = new AttributesFactory(); + // Create region. + RegionFactory factory = cache.createRegionFactory(); factory.setDataPolicy(DataPolicy.REPLICATE); factory.setScope(Scope.DISTRIBUTED_ACK); - Region testRegion = cache.createRegion("test-cq", factory.create()); + Region testRegion = factory.create("test-cq"); System.out.println("Test region, " + testRegion.getFullPath() + ", created in cache."); - + // Start Cache Server. CacheServer server = cache.addCacheServer(); server.setPort(40404); - server.setNotifyBySubscription(true); server.start(); ForkUtil.createControlFile(CacheServerProcess.class.getName()); diff --git a/src/test/java/org/springframework/data/gemfire/fork/FunctionCacheServerProcess.java b/src/test/java/org/springframework/data/gemfire/fork/FunctionCacheServerProcess.java index 616a8c59..c48d7f78 100644 --- a/src/test/java/org/springframework/data/gemfire/fork/FunctionCacheServerProcess.java +++ b/src/test/java/org/springframework/data/gemfire/fork/FunctionCacheServerProcess.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2012 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. @@ -20,48 +20,45 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Properties; - import org.springframework.data.gemfire.ForkUtil; -import org.springframework.data.gemfire.function.MethodInvokingFunction; -import com.gemstone.gemfire.cache.AttributesFactory; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheFactory; import com.gemstone.gemfire.cache.DataPolicy; import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionFactory; import com.gemstone.gemfire.cache.Scope; import com.gemstone.gemfire.cache.execute.FunctionAdapter; import com.gemstone.gemfire.cache.execute.FunctionContext; import com.gemstone.gemfire.cache.execute.FunctionService; import com.gemstone.gemfire.cache.server.CacheServer; -import com.gemstone.gemfire.distributed.DistributedSystem; /** * @author Costin Leau + * @author David Turanski */ public class FunctionCacheServerProcess { - static Region testRegion; + static Region testRegion; public static void main(String[] args) throws Exception { Properties props = new Properties(); - props.setProperty("name", "CqServer"); + props.setProperty("name", "FunctionServer"); props.setProperty("log-level", "config"); - - System.out.println("\nConnecting to the distributed system and creating the cache."); - DistributedSystem ds = DistributedSystem.connect(props); - Cache cache = CacheFactory.create(ds); + props.setProperty("groups","g1,g2,g3"); + + + Cache cache = new CacheFactory(props).create(); // Create region. - AttributesFactory factory = new AttributesFactory(); + RegionFactory factory = cache.createRegionFactory(); factory.setDataPolicy(DataPolicy.REPLICATE); factory.setScope(Scope.DISTRIBUTED_ACK); - testRegion = cache.createRegion("test-function", factory.create()); + testRegion = factory.create("test-function"); System.out.println("Test region, " + testRegion.getFullPath() + ", created in cache."); // Start Cache Server. CacheServer server = cache.addCacheServer(); server.setPort(40404); - server.setNotifyBySubscription(true); server.start(); System.out.println("Server started"); @@ -73,9 +70,10 @@ public class FunctionCacheServerProcess { System.out.println("Registering ServerFunction"); FunctionService.registerFunction(new ServerFunction()); System.out.println("Registered ServerFunction"); - - FunctionService.registerFunction(new MethodInvokingFunction()); - System.out.println("Registered MethodInvokingFunction"); + + System.out.println("Registering EchoFunction"); + FunctionService.registerFunction(new EchoFunction()); + System.out.println("Registered EchoFunction"); ForkUtil.createControlFile(FunctionCacheServerProcess.class.getName()); @@ -106,5 +104,30 @@ public class FunctionCacheServerProcess { } + static class EchoFunction extends FunctionAdapter { + + /* (non-Javadoc) + * @see com.gemstone.gemfire.cache.execute.FunctionAdapter#execute(com.gemstone.gemfire.cache.execute.FunctionContext) + */ + @Override + public void execute(FunctionContext functionContext) { + Object[] args = (Object[])functionContext.getArguments(); + for (int i=0; i< args.length; i++){ + if (i == args.length-1){ + functionContext.getResultSender().lastResult(args[i]); + } else { + functionContext.getResultSender().sendResult(args[i]); + } + } + + + } + @Override + public String getId() { + return "echoFunction"; + } + + } + } diff --git a/src/test/java/org/springframework/data/gemfire/fork/SpringCacheServerProcess.java b/src/test/java/org/springframework/data/gemfire/fork/SpringCacheServerProcess.java new file mode 100644 index 00000000..017e8cf1 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/fork/SpringCacheServerProcess.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2012 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.fork; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.gemfire.ForkUtil; + +/** + * @author David Turanski + * + */ +public class SpringCacheServerProcess { + public static void main(String[] args) { + try { + new ClassPathXmlApplicationContext(args[0]); + ForkUtil.createControlFile(SpringCacheServerProcess.class.getName()); + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); + System.out.println("Waiting for shutdown"); + bufferedReader.readLine(); + + + + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/function/FunctionArgumentResolverTest.java b/src/test/java/org/springframework/data/gemfire/function/FunctionArgumentResolverTest.java new file mode 100644 index 00000000..5137fecf --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/FunctionArgumentResolverTest.java @@ -0,0 +1,287 @@ +/* + * Copyright 2002-2012 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.function; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.junit.Test; +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.RegionData; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.execute.RegionFunctionContext; + +/** + * @author David Turanski + * + */ +public class FunctionArgumentResolverTest { + + @Test + public void testDefaultFunctionArgumentResolverSingleArg() { + FunctionArgumentResolver far = new DefaultFunctionArgumentResolver(); + + FunctionContext functionContext = mock(FunctionContext.class); + + + when(functionContext.getArguments()).thenReturn("hello"); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(1,args.length); + assertEquals("hello", args[0]); + } + + @Test + public void testDefaultFunctionArgumentResolverSingleArgAsArray() { + FunctionArgumentResolver far = new DefaultFunctionArgumentResolver(); + + FunctionContext functionContext = mock(FunctionContext.class); + + + when(functionContext.getArguments()).thenReturn(new String[]{"hello"}); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(1,args.length); + assertEquals("hello", args[0]); + } + + @Test + public void testMethodWithNoSpecialArgs() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + + Method method = TestFunction.class.getDeclaredMethod("methodWithNoSpecialArgs", String.class,int.class,boolean.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{"hello",0,false}; + when(functionContext.getArguments()).thenReturn(originalArgs); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(originalArgs.length, args.length); + + int i = 0; + for (Object arg: args) { + assertSame(originalArgs[i++], arg); + } + + } + + @Test + public void testMethodWithRegionType() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + @SuppressWarnings("unchecked") + Region region = mock(Region.class); + + + Method method = TestFunction.class.getDeclaredMethod("methodWithRegionType", String.class,Region.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{"hello"}; + when(functionContext.getArguments()).thenReturn(originalArgs); + when(functionContext.getDataSet()).thenReturn(region); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(originalArgs.length + 1, args.length); + + int i = 0; + for (Object arg: args) { + if (i != 1) { + assertSame(originalArgs[i++], arg); + } else { + assertSame(region,arg); + } + } + + } + + @Test + public void testMethodWithOneArgRegionType() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + @SuppressWarnings("unchecked") + Region region = mock(Region.class); + + + Method method = TestFunction.class.getDeclaredMethod("methodWithOneArgRegionType", Region.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{}; + when(functionContext.getArguments()).thenReturn(originalArgs); + when(functionContext.getDataSet()).thenReturn(region); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(1, args.length); + assertSame(region,args[0]); + + } + + @Test + public void testMethodWithAnnotatedRegion() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + @SuppressWarnings("unchecked") + Region region = mock(Region.class); + + + Method method = TestFunction.class.getDeclaredMethod("methodWithAnnotatedRegion", Map.class, String.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{"hello"}; + when(functionContext.getArguments()).thenReturn(originalArgs); + when(functionContext.getDataSet()).thenReturn(region); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(2, args.length); + assertSame(region,args[0]); + assertSame(originalArgs[0],args[1]); + + } + + @Test + public void testMethodWithFunctionContext() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + @SuppressWarnings("unchecked") + Region region = mock(Region.class); + + + Method method = TestFunction.class.getDeclaredMethod("methodWithFunctionContext", Map.class, String.class, FunctionContext.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{"hello"}; + when(functionContext.getArguments()).thenReturn(originalArgs); + when(functionContext.getDataSet()).thenReturn(region); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(3, args.length); + assertSame(region,args[0]); + assertSame(originalArgs[0],args[1]); + assertSame(functionContext,args[2]); + } + + @SuppressWarnings("unchecked") + @Test + public void testMethodWithFilterAndRegion() throws SecurityException, NoSuchMethodException { + RegionFunctionContext functionContext = mock(RegionFunctionContext.class); + Region region = mock(Region.class); + + + Method method = TestFunction.class.getDeclaredMethod("methodWithFilterAndRegion", Map.class, Set.class, Object.class); + FunctionArgumentResolver far = new FunctionContextInjectingArgumentResolver(method); + + + Object[] originalArgs = new Object[]{new Object()}; + when(functionContext.getArguments()).thenReturn(originalArgs); + when(functionContext.getDataSet()).thenReturn(region); + @SuppressWarnings("rawtypes") + Set keys = new HashSet(); + when(functionContext.getFilter()).thenReturn(keys); + + Object[] args = far.resolveFunctionArguments(functionContext); + + assertEquals(3, args.length); + assertSame(region,args[0]); + assertSame(originalArgs[0],args[2]); + assertSame(keys,args[1]); + } + + + @Test + public void testMethodWithMultipleRegionData() throws SecurityException, NoSuchMethodException { + + Method method = TestFunction.class.getDeclaredMethod("methodWithMultipleRegionData", Map.class, Map.class); + + try { + new FunctionContextInjectingArgumentResolver(method); + fail("Should throw exception"); + } catch (Exception e) { + + } + + } + + + @Test + public void testMethodWithMultipleRegions() throws SecurityException, NoSuchMethodException { + + Method method = TestFunction.class.getDeclaredMethod("methodWithMultipleRegions", Region.class, Map.class); + + try { + new FunctionContextInjectingArgumentResolver(method); + fail("Should throw exception"); + } catch (Exception e) { + + } + } + + + @Test + public void testMethodWithInvalidTypeForAnnotation() throws SecurityException, NoSuchMethodException { + + Method method = TestFunction.class.getDeclaredMethod("methodWithInvalidTypeForAnnotation", Region.class); + + try { + new FunctionContextInjectingArgumentResolver(method); + fail("Should throw exception"); + } catch (Exception e) { + + } + } + + + @Test + public void testMethodWithMultipleFunctionContext() throws SecurityException, NoSuchMethodException { + + Method method = TestFunction.class.getDeclaredMethod("methodWithMultipleFunctionContext", FunctionContext.class, FunctionContext.class); + + try { + new FunctionContextInjectingArgumentResolver(method); + fail("Should throw exception"); + } catch (Exception e) { + + } + } + + static class TestFunction { + public void methodWithNoSpecialArgs(String s1, int i1, boolean b1) {} + public void methodWithRegionType(String s1, Region region){} + public void methodWithOneArgRegionType(Region region){} + public void methodWithAnnotatedRegion(@RegionData Map data, String s1){} + public void methodWithFunctionContext(@RegionData Map data, String s1, FunctionContext fc){} + public void methodWithFilterAndRegion(@RegionData Map region, @Filter Set keys, Object arg){} + //Invalid Method Signatures + public void methodWithMultipleRegionData(@RegionData Map r1, @RegionData Map r2){} + public void methodWithMultipleRegions(Region r1, @RegionData Map r2){} + public void methodWithInvalidTypeForAnnotation(@Filter Region r1){} + public void methodWithMultipleFunctionContext(FunctionContext fc1, FunctionContext fc2){} + + } +} diff --git a/src/test/java/org/springframework/data/gemfire/function/FunctionExecutionTests.java b/src/test/java/org/springframework/data/gemfire/function/FunctionExecutionTests.java deleted file mode 100644 index a6584d92..00000000 --- a/src/test/java/org/springframework/data/gemfire/function/FunctionExecutionTests.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.data.gemfire.ForkUtil; -import org.springframework.data.gemfire.fork.FunctionCacheServerProcess; -import org.springframework.data.gemfire.function.foo.Foo; - -import com.gemstone.gemfire.cache.Region; -import com.gemstone.gemfire.cache.client.ClientCache; -import com.gemstone.gemfire.cache.client.ClientCacheFactory; -import com.gemstone.gemfire.cache.client.ClientRegionFactory; -import com.gemstone.gemfire.cache.client.ClientRegionShortcut; -import com.gemstone.gemfire.cache.client.Pool; -import com.gemstone.gemfire.cache.client.PoolFactory; -import com.gemstone.gemfire.cache.client.PoolManager; - -/** - * @author David Turanski - * - */ -public class FunctionExecutionTests { - - private static ClientCache cache = null; - - private static Pool pool = null; - - private static Region clientRegion = null; - - @BeforeClass - public static void startUp() throws Exception { - ForkUtil.cacheServer(FunctionCacheServerProcess.class); - - Properties props = new Properties(); - props.put("mcast-port", "0"); - props.put("name", "function-client"); - props.put("log-level", "warning"); - - ClientCacheFactory ccf = new ClientCacheFactory(props); - ccf.setPoolSubscriptionEnabled(true); - cache = ccf.create(); - - PoolFactory pf = PoolManager.createFactory(); - pf.addServer("localhost", 40404); - pf.setSubscriptionEnabled(true); - pool = pf.create("client"); - - ClientRegionFactory crf = cache.createClientRegionFactory(ClientRegionShortcut.PROXY); - crf.setPoolName("client"); - clientRegion = crf.create("test-function"); - } - - @AfterClass - public static void cleanUp() { - ForkUtil.sendSignal(); - if (clientRegion != null) { - clientRegion.destroyRegion(); - } - if (pool != null) { - pool.destroy(); - pool = null; - } - - if (cache != null) { - cache.close(); - } - cache = null; - } - - @Test - public void testRegionExecution() { - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class, "oneArg", "one"); - RegionFunctionExecution execution = new RegionFunctionExecution(clientRegion, - new MethodInvokingFunction(), invocation); - - int result = execution.executeAndExtract(); - assertEquals(1, result); - } - - @Test - public void testRegionExecutionWithRegisteredFunction() { - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class, "oneArg", "one"); - RegionFunctionExecution execution = new RegionFunctionExecution(clientRegion, - new MethodInvokingFunction().getId(), invocation); - int result = execution.executeAndExtract(); - assertEquals(1, result); - } - - // TODO: Filter only works on partitioned region. No effect here, but server - // won't start with a partitioned region. Probably because no locator - @Test - public void testRegionExecutionWithFilter() { - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class, "oneArg", "one"); - Set keys = new HashSet(); - keys.add("two"); - RegionFunctionExecution execution = new RegionFunctionExecution(clientRegion, - new MethodInvokingFunction().getId(), invocation); - execution.setKeys(keys); - Integer result = execution.executeAndExtract(); - // assertEquals(null,result.get(0)); - assertEquals(1, result.intValue()); - } - - @Test - public void testRegionExecutionForMap() { - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class, "getMapWithNoArgs"); - RegionFunctionExecution> execution = new RegionFunctionExecution>( - clientRegion, new MethodInvokingFunction().getId(), invocation); - execution.execute(); - - Map result = execution.executeAndExtract(); - assertTrue(result.containsKey("one")); - assertEquals(1, result.get("one").intValue()); - } - - @Test - public void testServersExecutionWithRegisteredFunction() { - assertNull(clientRegion.get("four")); - ServersFunctionExecution execution = new ServersFunctionExecution(cache, "serverFunction", "four", new Integer( - 4)); - execution.execute(); - assertNotNull(clientRegion.get("four")); - } - - @Test - public void testServerExecutionWithRegisteredFunction() { - assertNull(clientRegion.get("five")); - ServerFunctionExecution execution = new ServerFunctionExecution(cache, "serverFunction", "five", new Integer(5)); - Object result = execution.executeAndExtract(); - assertNull(result); - assertNotNull(clientRegion.get("five")); - } - -} diff --git a/src/test/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBeanTest.java deleted file mode 100644 index c7a0aca1..00000000 --- a/src/test/java/org/springframework/data/gemfire/function/GemfireFunctionProxyFactoryBeanTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -/** - * @author David Turanski - * - */ - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.gemfire.function.foo.Foo; -import org.springframework.data.gemfire.function.foo.IFoo; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.gemstone.gemfire.cache.Region; - -/** - * - * @author David Turanski - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -public class GemfireFunctionProxyFactoryBeanTest { - - private GemfireFunctionOperations functionOperations; - static Log logger = LogFactory.getLog(GemfireFunctionProxyFactoryBeanTest.class); - - @Autowired - private IFoo foo; - - @Autowired - private ApplicationContext context; - - private Region region; - - @SuppressWarnings("unchecked") - @Before - public void setUp() { - assertNotNull(foo); - functionOperations = mock(GemfireFunctionOperations.class); - - region = context.getBean("someRegion",Region.class); - assertNotNull(region); - - region.put("one",1); - region.put("two",2); - region.put("three",3); - } - - @Test - public void testInstance() throws Exception { - GemfireFunctionOperations functionOperations = mock(GemfireFunctionOperations.class); - GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class,Foo.class.getName(),functionOperations); - IFoo foo = (IFoo)proxy.getObject(); - assertTrue(foo instanceof FilterAware); - } - - @Test - public void testSetFilter() throws Exception { - - GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class,Foo.class.getName(),functionOperations); - IFoo foo = (IFoo)proxy.getObject(); - - Set filter = Collections.singleton("foo"); - Object obj = ((FilterAware) foo).setFilter(filter); - assertSame(obj,foo); - assertSame(filter,proxy.getFilter()); - - } - - - @Test - public void testRemoteExecutionOneArg() { - assertEquals(1,foo.oneArg("one").intValue()); - ((FilterAware)foo).setFilter(Collections.singleton("one")); - assertEquals(1,foo.oneArg("one").intValue()); - } - - @Test - public void testRemoteExecutionTwoArg() { - assertEquals(3,foo.twoArg("one","two").intValue()); - } - - - @Test - public void testRemoteExectionArrayList() { - ArrayList ints = new ArrayList(Arrays.asList(new Integer[]{1,2,3})); - assertEquals(1,foo.collections(ints).get(0).intValue()); - } - - @Test - public void testRemoteExectionMap() { - Map result = foo.getMapWithNoArgs(); - assertEquals(1,result.get("one").intValue()); - } - - @After - public void tearDown() { - - } -} - - diff --git a/src/test/java/org/springframework/data/gemfire/function/MethodInvokingFunctionTests.java b/src/test/java/org/springframework/data/gemfire/function/MethodInvokingFunctionTests.java deleted file mode 100644 index 5db5de87..00000000 --- a/src/test/java/org/springframework/data/gemfire/function/MethodInvokingFunctionTests.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2002-2011 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.function; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.data.gemfire.ForkUtil; -import org.springframework.data.gemfire.GemfireCallback; -import org.springframework.data.gemfire.GemfireTemplate; -import org.springframework.data.gemfire.function.foo.Foo; - -import com.gemstone.gemfire.GemFireCheckedException; -import com.gemstone.gemfire.GemFireException; -import com.gemstone.gemfire.cache.Region; -import com.gemstone.gemfire.cache.client.ClientCache; -import com.gemstone.gemfire.cache.client.ClientCacheFactory; -import com.gemstone.gemfire.cache.client.ClientRegionFactory; -import com.gemstone.gemfire.cache.client.ClientRegionShortcut; -import com.gemstone.gemfire.cache.client.Pool; -import com.gemstone.gemfire.cache.client.PoolFactory; -import com.gemstone.gemfire.cache.client.PoolManager; -import com.gemstone.gemfire.cache.execute.Execution; -import com.gemstone.gemfire.cache.execute.FunctionService; -import com.gemstone.gemfire.cache.execute.ResultCollector; - -/** - * @author David Turanski - * - */ -public class MethodInvokingFunctionTests { - private static ClientCache cache = null; - - private static MethodInvokingFunction methodInvokingFunction = new MethodInvokingFunction(); - private static Pool pool = null; - - private static Region clientRegion = null; - - private static GemfireTemplate gemfireTemplate; - - @BeforeClass - public static void startUp() throws Exception { - ForkUtil.cacheServer(); - - Properties props = new Properties(); - props.put("mcast-port", "0"); - props.put("name", "cq-client"); - props.put("log-level", "warning"); - - ClientCacheFactory ccf = new ClientCacheFactory(props); - ccf.setPoolSubscriptionEnabled(true); - cache = ccf.create(); - - PoolFactory pf = PoolManager.createFactory(); - pf.addServer("localhost", 40404); - pf.setSubscriptionEnabled(true); - pool = pf.create("client"); - - ClientRegionFactory crf = cache.createClientRegionFactory(ClientRegionShortcut.LOCAL); - crf.setPoolName("client"); - clientRegion = crf.create("test-cq"); - - gemfireTemplate = new GemfireTemplate(clientRegion); - - ForkUtil.sendSignal(); - Thread.sleep(500); - } - - @AfterClass - public static void cleanUp() { - ForkUtil.sendSignal(); - if (clientRegion != null) { - clientRegion.destroyRegion(); - } - if (pool != null) { - pool.destroy(); - pool = null; - } - - if (cache != null) { - cache.close(); - } - cache = null; - } - - @Test - public void testInvokeRemoteFunctionOneArg() throws Exception { - - gemfireTemplate.setExposeNativeRegion(true); - - Integer val = gemfireTemplate.execute(new GemfireCallback() { - - public Integer doInGemfire(@SuppressWarnings("rawtypes") Region region) throws GemFireCheckedException, GemFireException { - - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"oneArg","one"); - Execution execution = FunctionService.onRegion(region); - ResultCollector resultsCollector = execution.withArgs(invocation).execute(methodInvokingFunction); - ArrayList result = (ArrayList)resultsCollector.getResult(); - return (Integer)result.get(0); - } - }); - - assertEquals(1,val.intValue()); - } - - @Test - public void testInvokeRemoteFunctionTwoArgs() throws Exception { - - gemfireTemplate.setExposeNativeRegion(true); - - Integer val = gemfireTemplate.execute(new GemfireCallback() { - - public Integer doInGemfire(@SuppressWarnings("rawtypes") Region region) throws GemFireCheckedException, GemFireException { - - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"twoArg","one","three"); - Execution execution = FunctionService.onRegion(region); - ResultCollector resultsCollector = execution.withArgs(invocation).execute(methodInvokingFunction); - ArrayList result = (ArrayList)resultsCollector.getResult(); - return (Integer)result.get(0); - } - }); - - assertEquals(4,val.intValue()); - - } - - @Test - public void testInvokeRemoteFunctionCollections() throws Exception { - - gemfireTemplate.setExposeNativeRegion(true); - - List val = gemfireTemplate.execute(new GemfireCallback>() { - - @SuppressWarnings("unchecked") - public List doInGemfire(@SuppressWarnings("rawtypes") Region region) throws GemFireCheckedException, GemFireException { - ArrayList list = new ArrayList(Arrays.asList(new Integer[]{1,2,3,4,5})); - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"collections",list); - Execution execution = FunctionService.onRegion(region); - - ResultCollector resultsCollector = execution.withArgs(invocation).execute(methodInvokingFunction); - ArrayList result = (ArrayList)resultsCollector.getResult(); - //If result type is a list, Gemfire merges it into the results. - return (List)result; - } - }); - - assertEquals(5,val.size()); - for (int i=0; i<5; i++) { - assertEquals(i+1,val.get(i).intValue()); - } - } - - @Test - public void testInvokeRemoteFunctionMap() throws Exception { - - gemfireTemplate.setExposeNativeRegion(true); - - Map val = gemfireTemplate.execute(new GemfireCallback>() { - - @SuppressWarnings("unchecked") - public Map doInGemfire(@SuppressWarnings("rawtypes") Region region) throws GemFireCheckedException, GemFireException { - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"getMapWithNoArgs"); - Execution execution = FunctionService.onRegion(region); - ResultCollector resultsCollector = execution.withArgs(invocation).execute(methodInvokingFunction); - ArrayList result = (ArrayList)resultsCollector.getResult(); - return (Map)result.get(0); - } - }); - - assertEquals(3,val.size()); - for (int i=0; i<3; i++) { - assertTrue(val.values().contains(i+1)); - } - } -} diff --git a/src/test/java/org/springframework/data/gemfire/function/config/AnnotationDrivenFunctionsTest.java b/src/test/java/org/springframework/data/gemfire/function/config/AnnotationDrivenFunctionsTest.java index 2209eade..9e120cca 100644 --- a/src/test/java/org/springframework/data/gemfire/function/config/AnnotationDrivenFunctionsTest.java +++ b/src/test/java/org/springframework/data/gemfire/function/config/AnnotationDrivenFunctionsTest.java @@ -17,6 +17,7 @@ import static org.junit.Assert.assertTrue; import java.util.List; import java.util.Map; +import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; @@ -60,6 +61,13 @@ public class AnnotationDrivenFunctionsTest { assertTrue(function.isHA()); assertTrue(function.optimizeForWrite()); assertTrue(function.hasResult()); + + + assertTrue(FunctionService.isRegistered("injectFilter")); + function = FunctionService.getFunction("injectFilter"); + assertTrue(function.isHA()); + assertTrue(function.optimizeForWrite()); + assertTrue(function.hasResult()); } @Component @@ -81,8 +89,8 @@ public class AnnotationDrivenFunctionsTest { return null; } - @GemfireFunction(id="injectMultipleRegions", HA=true,optimizeForWrite=true) - public List injectMultipleRegions (@RegionData("someRegion") Map someRegion, @RegionData("someOtherRegion") Map someOtherRegion) { + @GemfireFunction(id="injectFilter", HA=true,optimizeForWrite=true) + public List injectFilter (@Filter Set keySet) { return null; } } diff --git a/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionClientCacheTests.java b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionClientCacheTests.java new file mode 100644 index 00000000..f608b25a --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionClientCacheTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2012 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.function.config; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.ImportResource; +import org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions; +import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean; +import org.springframework.data.gemfire.function.execution.OnRegionFunctionProxyFactoryBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.Pool; + +/** + * @author David Turanski + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes={TestClientCacheConfig.class}) +public class FunctionExecutionClientCacheTests { + @Autowired + ApplicationContext context; + + @Test + public void testContextCreated() throws Exception { + + //String name ="testClientOnRegionFunction"; + String name ="testClientOnServerFunction"; + + // GemfireFunctionProxyFactoryBean factoryBean = (GemfireFunctionProxyFactoryBean)context.getBean("&"+name); + + ClientCache cache = context.getBean("gemfireCache",ClientCache.class); + Pool pool = context.getBean("gemfirePool",Pool.class); + assertEquals("gemfirePool", pool.getName()); + assertEquals(1, cache.getDefaultPool().getServers().size()); + assertEquals(pool.getServers().get(0), cache.getDefaultPool().getServers().get(0)); + + + context.getBean("r1",Region.class); + //ComponentScan s; + //FilterType f; + + } + +} + + +@ImportResource("/org/springframework/data/gemfire/function/config/FunctionExecutionCacheClientTests-context.xml") +@EnableGemfireFunctionExecutions (basePackages = "org.springframework.data.gemfire.function.config.three", + excludeFilters = { + @ComponentScan.Filter(type=FilterType.ANNOTATION, value=OnRegion.class)/*, + @ComponentScan.Filter(type=FilterType.ANNOTATION, value=OnServer.class)*/ + } +) +@Configuration +class TestClientCacheConfig { + +} + + + diff --git a/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProviderTest.java b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProviderTest.java new file mode 100644 index 00000000..2e239730 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionComponentProviderTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2012 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.function.config; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.type.filter.AssignableTypeFilter; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.data.gemfire.function.config.one.TestFunctionExecution; + +/** + * @author David Turanski + * + */ +public class FunctionExecutionComponentProviderTest { + + @Test + public void testDiscovery() throws ClassNotFoundException { + List includeFilters = new ArrayList(); + FunctionExecutionComponentProvider provider = new FunctionExecutionComponentProvider(includeFilters,AnnotationFunctionExecutionConfigurationSource.getFunctionExecutionAnnotationTypes()); + Set candidates = provider.findCandidateComponents(this.getClass().getPackage().getName()+".one"); + + ScannedGenericBeanDefinition bd = null; + + for (BeanDefinition candidate: candidates) { + if (candidate.getBeanClassName().equals(TestFunctionExecution.class.getName())) { + bd = (ScannedGenericBeanDefinition)candidate; + } + } + + assertNotNull(bd); + + } + + @Test + public void testExcludeFilter() throws ClassNotFoundException { + List includeFilters = new ArrayList(); + FunctionExecutionComponentProvider provider = new FunctionExecutionComponentProvider(includeFilters,AnnotationFunctionExecutionConfigurationSource.getFunctionExecutionAnnotationTypes()); + + provider.addExcludeFilter(new AssignableTypeFilter(TestFunctionExecution.class)); + + Set candidates = provider.findCandidateComponents(this.getClass().getPackage().getName()+".one"); + + for (BeanDefinition candidate: candidates) { + if (candidate.getBeanClassName().equals(TestFunctionExecution.class.getName())) { + fail(TestFunctionExecution.class.getName() + " not excluded"); + } + } + } + +} + + diff --git a/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests.java new file mode 100644 index 00000000..a703e772 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2012 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.function.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.data.gemfire.TestUtils; +import org.springframework.data.gemfire.function.config.EnableGemfireFunctionExecutions; +import org.springframework.data.gemfire.function.config.two.TestOnRegionFunction; +import org.springframework.data.gemfire.function.execution.GemfireOnRegionFunctionTemplate; +import org.springframework.data.gemfire.function.execution.OnRegionFunctionProxyFactoryBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.Pool; + +/** + * @author David Turanski + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes={TestConfig.class}) +public class FunctionExecutionIntegrationTests { + @Autowired + ApplicationContext context; + + + @Test + public void testProxyFactoryBeanCreated() throws Exception { + OnRegionFunctionProxyFactoryBean factoryBean = (OnRegionFunctionProxyFactoryBean)context.getBean("&testFunction"); + Class serviceInterface = TestUtils.readField("serviceInterface",factoryBean); + assertEquals(serviceInterface, TestOnRegionFunction.class); + + Region r1 = context.getBean("r1",Region.class); + + GemfireOnRegionFunctionTemplate template = TestUtils.readField("gemfireFunctionOperations",factoryBean); + + assertSame(r1, TestUtils.readField("region",template)); + } + +} + + +@ImportResource("/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests-context.xml") +@EnableGemfireFunctionExecutions(basePackages = "org.springframework.data.gemfire.function.config.two") +@Configuration +class TestConfig { + +} + + + diff --git a/src/test/java/org/springframework/data/gemfire/function/config/one/TestFunctionExecution.java b/src/test/java/org/springframework/data/gemfire/function/config/one/TestFunctionExecution.java new file mode 100644 index 00000000..b72f8505 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/one/TestFunctionExecution.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-2012 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.function.config.one; + +import java.util.Set; + +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.data.gemfire.function.config.OnMember; + +@OnMember +public interface TestFunctionExecution { + @FunctionId("f1") + public String getString(Object arg1, @Filter Set keys) ; + + @FunctionId("f2") + public String getString(Object arg1) ; + +} \ No newline at end of file diff --git a/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnRegionFunction.java b/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnRegionFunction.java new file mode 100644 index 00000000..3b29acf8 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnRegionFunction.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2012 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.function.config.three; + +import java.util.Set; + +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.data.gemfire.function.config.OnRegion; + +/** + * @author David Turanski + * + */ +@OnRegion(id="testClientOnRegionFunction", region="r1") +public interface TestClientOnRegionFunction { + @FunctionId("f1") + public String getString(Object arg1, @Filter Set keys) ; + + @FunctionId("f2") + public String getString(Object arg1) ; +} + + + diff --git a/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnServerFunction.java b/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnServerFunction.java new file mode 100644 index 00000000..d9fa0130 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/three/TestClientOnServerFunction.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2012 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.function.config.three; + +import java.util.Set; + +import org.springframework.data.gemfire.config.GemfireConstants; +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.data.gemfire.function.config.OnServer; + +/** + * @author David Turanski + * + */ +@OnServer(id="testClientOnServerFunction",pool="gemfirePool") +public interface TestClientOnServerFunction { + @FunctionId("f1") + public String getString(Object arg1, @Filter Set keys) ; + + @FunctionId("f2") + public String getString(Object arg1) ; +} diff --git a/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction.java b/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction.java new file mode 100644 index 00000000..14694276 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2012 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.function.config.two; + +import java.util.Set; + +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.data.gemfire.function.config.OnRegion; +import org.springframework.data.gemfire.function.config.OnServer; + +/** + * @author David Turanski + * + */ +@OnRegion(id="testFunction", region="r1") +public interface TestOnRegionFunction { + @FunctionId("f1") + public String getString(Object arg1, @Filter Set keys) ; + + @FunctionId("f2") + public String getString(Object arg1) ; +} + + + diff --git a/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction2.java b/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction2.java new file mode 100644 index 00000000..be13b4fc --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/config/two/TestOnRegionFunction2.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2012 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.function.config.two; + +import java.util.Set; + +import org.springframework.data.gemfire.function.config.Filter; +import org.springframework.data.gemfire.function.config.FunctionId; +import org.springframework.data.gemfire.function.config.OnServer; + +/** + * @author David Turanski + * + */ +@OnServer(id="testFunction2") +public interface TestOnRegionFunction2 { + @FunctionId("f1") + public String getString(Object arg1, @Filter Set keys) ; + + @FunctionId("f2") + public String getString(Object arg1) ; +} diff --git a/src/test/java/org/springframework/data/gemfire/function/execution/FunctionExecutionTests.java b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionExecutionTests.java new file mode 100644 index 00000000..9660b5be --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionExecutionTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2011 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.function.execution; + +import static org.junit.Assert.assertEquals; + +import java.util.Iterator; +import java.util.Properties; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.data.gemfire.ForkUtil; +import org.springframework.data.gemfire.fork.FunctionCacheServerProcess; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.ClientCacheFactory; +import com.gemstone.gemfire.cache.client.ClientRegionFactory; +import com.gemstone.gemfire.cache.client.ClientRegionShortcut; +import com.gemstone.gemfire.cache.client.Pool; +import com.gemstone.gemfire.cache.client.PoolFactory; +import com.gemstone.gemfire.cache.client.PoolManager; + +/** + * @author David Turanski + * + */ +public class FunctionExecutionTests { + + private static ClientCache cache = null; + + private static Pool pool = null; + + private static Region clientRegion = null; + + @BeforeClass + public static void startUp() throws Exception { + // Registers function "echoFunction" + ForkUtil.cacheServer(FunctionCacheServerProcess.class); + + Properties props = new Properties(); + props.put("mcast-port", "0"); + props.put("name", "function-client"); + props.put("log-level", "warning"); + + ClientCacheFactory ccf = new ClientCacheFactory(props); + ccf.setPoolSubscriptionEnabled(true); + cache = ccf.create(); + + PoolFactory pf = PoolManager.createFactory(); + pf.addServer("localhost", 40404); + pf.setSubscriptionEnabled(true); + pool = pf.create("client"); + + ClientRegionFactory crf = cache.createClientRegionFactory(ClientRegionShortcut.PROXY); + crf.setPoolName("client"); + clientRegion = crf.create("test-function"); + } + + @AfterClass + public static void cleanUp() { + ForkUtil.sendSignal(); + if (clientRegion != null) { + clientRegion.destroyRegion(); + } + if (pool != null) { + pool.destroy(); + pool = null; + } + + if (cache != null) { + cache.close(); + } + cache = null; + } + + @Test + public void testBasicFunctionExecutions() { + verifyfunctionExecution(new RegionFunctionExecution(clientRegion)); + verifyfunctionExecution(new ServerFunctionExecution(cache)); + verifyfunctionExecution(new PoolServerFunctionExecution(pool)); + verifyfunctionExecution(new ServersFunctionExecution(cache)); + } + + + + private void verifyfunctionExecution(FunctionExecution functionExecution) { + Iterable results = functionExecution + .setArgs("1","2","3") + .setFunctionId("echoFunction") + .execute(); + + Iterator it = results.iterator(); + for (int i = 1; i<= 3; i++) { + assertEquals(String.valueOf(i),it.next()); + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java new file mode 100644 index 00000000..69ec52ab --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests.java @@ -0,0 +1,147 @@ +/* + * Copyright 2002-2012 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.function.execution; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.gemfire.ForkUtil; +import org.springframework.data.gemfire.fork.SpringCacheServerProcess; +import org.springframework.data.gemfire.function.config.GemfireFunction; +import org.springframework.data.gemfire.function.config.RegionData; +import org.springframework.stereotype.Component; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Region; + +/** + * @author David Turanski + * + */ + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class FunctionIntegrationTests { + @Resource(name="test-region") + Region region; + + @BeforeClass + public static void startUp() throws Exception { + ForkUtil.startCacheServer(SpringCacheServerProcess.class.getName() + " " + + " /org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-server-context.xml"); + } + + @AfterClass + public static void cleanUp() { + ForkUtil.sendSignal(); + } + + @Before + public void initializeRegion() { + region.put("one", 1); + region.put("two", 2); + region.put("three",3); + } + + @Test + public void testOnRegionFunctionExecution() { + + GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region); + + Iterable results; + results = template.execute("oneArg","two"); + assertEquals(2, results.iterator().next().intValue()); + + Set filter = new HashSet(); + filter.add("one"); + results = template.execute("oneArg",filter,"two"); + assertFalse(results.iterator().hasNext()); + + results = template.execute("twoArg","two","three"); + assertEquals(5, results.iterator().next().intValue()); + + Integer result = template.executeAndExtract("twoArg","two","three"); + assertEquals(5,result.intValue()); + } + + @Test + public void testCollectionReturnTypes() { + GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(region); + + Object result = template.executeAndExtract("getMapWithNoArgs"); + assertTrue(result instanceof Map); + @SuppressWarnings("unchecked") + Map map = (Map)result; + assertEquals(1,map.get("one").intValue()); + assertEquals(2,map.get("two").intValue()); + assertEquals(3,map.get("three").intValue()); + + result = template.execute("collections",Arrays.asList(new Integer[]{1,2,3,4,5})); + assertTrue(result.getClass().getName(),result instanceof List); + + List list = (List)result; + assertEquals(5, list.size()); + for (int i=1; i<= list.size(); i++) { + assertEquals(i,list.get(i-1)); + } + } + + /* + * This gets wrapped in a GemFire Function and registered on the forked server. + */ + @Component + public static class Foo { + + @GemfireFunction(id="oneArg") + public Integer oneArg(String key, @RegionData Map dataSet) { + return dataSet.get(key); + } + + @GemfireFunction(id="twoArg") + public Integer twoArg(String akey, String bkey, @RegionData Map dataSet) { + if (dataSet.get(akey) != null && dataSet.get(bkey) != null) { + return dataSet.get(akey) + dataSet.get(bkey); + } + return null; + } + + @GemfireFunction(id="collections") + public List collections(List args) { + return args; + } + + @GemfireFunction(id="getMapWithNoArgs") + public Map getMapWithNoArgs(@RegionData Map dataSet) { + if (dataSet.size() == 0) { + return null; + } + return new HashMap(dataSet); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBeanTests.java b/src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBeanTests.java new file mode 100644 index 00000000..6e574f58 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionProxyFactoryBeanTests.java @@ -0,0 +1,189 @@ +/* + * Copyright 2002-2011 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.function.execution; + +/** + * @author David Turanski + * + */ + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.aopalliance.intercept.MethodInvocation; +import org.junit.Before; +import org.junit.Test; +import org.springframework.data.gemfire.function.config.FunctionId; + +/** + * + * @author David Turanski + * + */ + +public class GemfireFunctionProxyFactoryBeanTests { + + private GemfireFunctionOperations functionOperations; + + @Before + public void setUp() { + functionOperations = mock(GemfireFunctionOperations.class); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testInvokeAndExtractWithAnnotatedFunctionId() throws Throwable { + + + GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class,functionOperations); + proxy.setFunctionId(IFoo.class.getName()); + + MethodInvocation invocation = new TestInvocation(IFoo.class).withMethodNameAndArgTypes("oneArg",String.class); + + List results = Arrays.asList(new Integer[]{1}); + + when(functionOperations.execute("oneArg",invocation.getArguments())).thenReturn(results); + + Object result = proxy.invoke(invocation); + assertTrue(result instanceof Integer); + assertEquals(new Integer(1),result); + } + + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testInvoke() throws Throwable { + + + GemfireFunctionProxyFactoryBean proxy = new GemfireFunctionProxyFactoryBean(IFoo.class, functionOperations); + proxy.setFunctionId(IFoo.class.getName()); + + MethodInvocation invocation = new TestInvocation(IFoo.class).withMethodNameAndArgTypes("collections",List.class); + + List results = Arrays.asList(new Integer[]{1,2,3}); + + when(functionOperations.execute(IFoo.class.getName() + ".collections",invocation.getArguments())).thenReturn(results); + + Object result = proxy.invoke(invocation); + assertTrue(result instanceof List); + assertEquals(3,((List)result).size()); + } + + + + static class TestInvocation implements MethodInvocation { + + private Class[] argTypes; + private Class clazz; + private String methodName; + private Object[] arguments; + + public TestInvocation(Class clazz) { + this.clazz = clazz; + } + + public TestInvocation withArguments(Object ...arguments){ + this.arguments = arguments; + return this; + } + + + + public TestInvocation withMethodNameAndArgTypes(String methodName,Class... argTypes) { + this.methodName = methodName; + this.argTypes = argTypes; + return this; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Invocation#getArguments() + */ + @Override + public Object[] getArguments() { + // TODO Auto-generated method stub + return this.arguments; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#proceed() + */ + @Override + public Object proceed() throws Throwable { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#getThis() + */ + @Override + public Object getThis() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.Joinpoint#getStaticPart() + */ + @Override + public AccessibleObject getStaticPart() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInvocation#getMethod() + */ + @Override + public Method getMethod() { + Method method = null; + try { + method = clazz.getMethod(methodName, argTypes); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return method; + } + + } + + public interface IFoo { + + @FunctionId("oneArg") + public abstract Integer oneArg(String key); + + public abstract Integer twoArg(String akey, String bkey); + + public abstract List collections(List args); + + public abstract Map getMapWithNoArgs(); + + } + + +} + + diff --git a/src/test/java/org/springframework/data/gemfire/function/GemfireFunctionTemplateTests.java b/src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionTemplateTests.java similarity index 66% rename from src/test/java/org/springframework/data/gemfire/function/GemfireFunctionTemplateTests.java rename to src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionTemplateTests.java index 7ea7df4c..5af790aa 100644 --- a/src/test/java/org/springframework/data/gemfire/function/GemfireFunctionTemplateTests.java +++ b/src/test/java/org/springframework/data/gemfire/function/execution/GemfireFunctionTemplateTests.java @@ -10,12 +10,11 @@ * 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.function; +package org.springframework.data.gemfire.function.execution; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import java.util.List; +import java.util.Iterator; import java.util.Properties; import org.junit.AfterClass; @@ -23,7 +22,6 @@ import org.junit.BeforeClass; import org.junit.Test; import org.springframework.data.gemfire.ForkUtil; import org.springframework.data.gemfire.fork.FunctionCacheServerProcess; -import org.springframework.data.gemfire.function.foo.Foo; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.client.ClientCache; @@ -84,29 +82,23 @@ public class GemfireFunctionTemplateTests { } cache = null; } - + @Test - public void testExecuteOnRegion() { - GemfireFunctionOperations functionTemplate = new GemfireFunctionTemplate(cache); - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"oneArg", "two"); - List result = functionTemplate.executeOnRegion(new MethodInvokingFunction().getId(),"test-function",invocation); - assertEquals(2,result.get(0).intValue()); - } - - @Test - public void testExecuteOnRegionAndExtract() { - GemfireFunctionOperations functionTemplate = new GemfireFunctionTemplate(cache); - RemoteMethodInvocation invocation = new RemoteMethodInvocation(Foo.class,"twoArg", "two","three"); - int result = functionTemplate.executeOnRegionAndExtract(new MethodInvokingFunction(),"test-function",invocation); - assertEquals(5,result); - } - - @Test - public void testExecuteOnServer() { - assertNull(clientRegion.get("four")); - GemfireFunctionOperations functionTemplate = new GemfireFunctionTemplate(cache); - functionTemplate.executeOnServers("serverFunction","four",4); - assertEquals(4,clientRegion.get("four").intValue()); - + public void testFunctionTemplates() { + verifyfunctionTemplateExecution( new GemfireOnServerFunctionTemplate(cache)); + verifyfunctionTemplateExecution( new GemfireOnServersFunctionTemplate(cache)); + verifyfunctionTemplateExecution( new GemfireOnRegionFunctionTemplate(clientRegion)); + verifyfunctionTemplateExecution( new GemfireOnServerFunctionTemplate(pool)); + verifyfunctionTemplateExecution( new GemfireOnServersFunctionTemplate(pool)); + } + + private void verifyfunctionTemplateExecution(GemfireFunctionOperations functionTemplate) { + Iterable results = functionTemplate.execute("echoFunction","1","2","3"); + + Iterator it = results.iterator(); + for (int i = 1; i<= 3; i++) { + assertEquals(String.valueOf(i),it.next()); + } } + } diff --git a/src/test/java/org/springframework/data/gemfire/function/foo/Foo.java b/src/test/java/org/springframework/data/gemfire/function/foo/Foo.java deleted file mode 100644 index 8bc7144e..00000000 --- a/src/test/java/org/springframework/data/gemfire/function/foo/Foo.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2002-2011 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.function.foo; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author David Turanski - * - */ -public class Foo implements IFoo { - - private Map dataSet; - - public Foo(Map dataSet) { - this.dataSet = dataSet; - } - - public Foo() { - - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.foo.IFoo#oneArg(java.lang.String) - */ - public Integer oneArg(String key) { - - return dataSet.get(key); - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.foo.IFoo#twoArg(java.lang.String, java.lang.String) - */ - public Integer twoArg(String akey, String bkey) { - if (dataSet.get(akey) != null && dataSet.get(bkey) != null) { - return dataSet.get(akey) + dataSet.get(bkey); - } - else { - return null; - } - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.foo.IFoo#collections(java.util.List) - */ - public List collections(List args) { - return args; - } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.foo.IFoo#getMapWithNoArgs() - */ - public Map getMapWithNoArgs() { - if (dataSet.size() == 0) { - return null; - } - - return new HashMap(dataSet); - } - -} diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTest.java index 56a45c6b..a70c6872 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTest.java @@ -15,8 +15,13 @@ */ package org.springframework.data.gemfire.repository.support; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collection; @@ -34,7 +39,6 @@ import org.springframework.data.repository.core.support.ReflectionEntityInformat import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.gemstone.gemfire.cache.CacheListener; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.RegionEvent; import com.gemstone.gemfire.cache.query.SelectResults; @@ -57,9 +61,10 @@ public class SimpleGemfireRepositoryIntegrationTest { SimpleGemfireRepository repository; - @SuppressWarnings("rawtypes") + RegionClearListener regionClearListener; + @SuppressWarnings("unchecked") @Before public void setUp() { regionClearListener = new RegionClearListener(); @@ -123,6 +128,7 @@ public class SimpleGemfireRepositoryIntegrationTest { assertThat(result, not(hasItems(dave))); } + @SuppressWarnings("rawtypes") public static class RegionClearListener extends CacheListenerAdapter { public boolean eventFired; @Override diff --git a/src/test/java/org/springframework/data/gemfire/serialization/AsmInstantiatorFactoryTest.java b/src/test/java/org/springframework/data/gemfire/serialization/AsmInstantiatorFactoryTest.java index 0e7c80aa..3a706b9e 100644 --- a/src/test/java/org/springframework/data/gemfire/serialization/AsmInstantiatorFactoryTest.java +++ b/src/test/java/org/springframework/data/gemfire/serialization/AsmInstantiatorFactoryTest.java @@ -36,6 +36,7 @@ import com.gemstone.gemfire.Instantiator; */ public class AsmInstantiatorFactoryTest { + @SuppressWarnings("serial") public static class SomeClass implements DataSerializable { public static boolean instantiated = false; diff --git a/src/test/java/org/springframework/data/gemfire/serialization/WiringInstantiatorTest.java b/src/test/java/org/springframework/data/gemfire/serialization/WiringInstantiatorTest.java index cf1ce7db..2d73d229 100644 --- a/src/test/java/org/springframework/data/gemfire/serialization/WiringInstantiatorTest.java +++ b/src/test/java/org/springframework/data/gemfire/serialization/WiringInstantiatorTest.java @@ -52,6 +52,7 @@ public class WiringInstantiatorTest { private WiringInstantiator instantiator; + @SuppressWarnings("serial") public static class AnnotatedBean implements DataSerializable { @Autowired Point point; @@ -69,6 +70,7 @@ public class WiringInstantiatorTest { } } + @SuppressWarnings("serial") public static class TemplateWiringBean implements DataSerializable { Point point; Beans beans; @@ -84,6 +86,7 @@ public class WiringInstantiatorTest { } } + @SuppressWarnings("serial") public static class TypeA implements DataSerializable { public void fromData(DataInput arg0) throws IOException, ClassNotFoundException { @@ -93,6 +96,7 @@ public class WiringInstantiatorTest { } } + @SuppressWarnings("serial") public static class TypeB implements DataSerializable { public void fromData(DataInput arg0) throws IOException, ClassNotFoundException { @@ -136,6 +140,7 @@ public class WiringInstantiatorTest { } public void testInstantiatorFactoryBean() throws Exception { + @SuppressWarnings("unchecked") List list = (List) ctx.getBean("instantiator-factory"); assertNotNull(list); assertEquals(2, list.size()); diff --git a/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionCacheClientTests-context.xml b/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionCacheClientTests-context.xml new file mode 100644 index 00000000..3c631caa --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionCacheClientTests-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests-context.xml b/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests-context.xml new file mode 100644 index 00000000..3b9f2b6a --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/function/config/FunctionExecutionIntegrationTests-context.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-context.xml b/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-context.xml new file mode 100644 index 00000000..416eb654 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-server-context.xml b/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-server-context.xml new file mode 100644 index 00000000..183e8ce8 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/function/execution/FunctionIntegrationTests-server-context.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +