Merge branch 'SGF_57_1'

This commit is contained in:
Costin Leau
2011-08-26 17:51:10 +03:00
16 changed files with 522 additions and 73 deletions

View File

@@ -0,0 +1,126 @@
/*
* Copyright 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.config;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.listener.ContinousQueryDefinition;
import org.springframework.data.gemfire.listener.ContinousQueryListenerContainer;
import org.springframework.data.gemfire.listener.adapter.ContinousQueryListenerAdapter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
* Parser for SGF <code>&lt;cq-listener-container&gt;</code> element.
*
* @author Costin Leau
*/
class GemfireListenerContainerParser extends AbstractSimpleBeanDefinitionParser {
@Override
protected Class<ContinousQueryListenerContainer> getBeanClass(Element element) {
return ContinousQueryListenerContainer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// parse attributes (but replace the value assignment with references)
NamedNodeMap attributes = element.getAttributes();
for (int x = 0; x < attributes.getLength(); x++) {
Attr attribute = (Attr) attributes.item(x);
if (isEligibleAttribute(attribute, parserContext)) {
String propertyName = extractPropertyName(attribute.getLocalName());
Assert.state(StringUtils.hasText(propertyName),
"Illegal property name returned from 'extractPropertyName(String)': cannot be null or empty.");
builder.addPropertyReference(propertyName, attribute.getValue());
}
}
String phase = element.getAttribute("phase");
if (StringUtils.hasText(phase)) {
builder.addPropertyValue("phase", phase);
}
postProcess(builder, element);
// parse nested listeners
List<Element> listDefs = DomUtils.getChildElementsByTagName(element, "listener");
if (!listDefs.isEmpty()) {
ManagedSet<BeanDefinition> listeners = new ManagedSet<BeanDefinition>(listDefs.size());
for (Element listElement : listDefs) {
listeners.add(parseListener(listElement));
}
builder.addPropertyValue("queryListeners", listeners);
}
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return (!"phase".equals(attributeName));
}
/**
* Parses a listener definition. Returns the listener bean reference definition (of a {@link ContinousQueryDefinition}).
*
* @param element
* @return
*/
private BeanDefinition parseListener(Element element) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ContinousQueryListenerAdapter.class);
builder.addConstructorArgReference(element.getAttribute("ref"));
String attr = element.getAttribute("method");
if (StringUtils.hasText(attr)) {
builder.addPropertyValue("defaultListenerMethod", attr);
}
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(ContinousQueryDefinition.class);
attr = element.getAttribute("name");
if (StringUtils.hasText(attr)) {
defBuilder.addConstructorArgValue(attr);
}
defBuilder.addConstructorArgValue(element.getAttribute("query"));
defBuilder.addConstructorArgValue(builder.getBeanDefinition());
attr = element.getAttribute("durable");
if (StringUtils.hasText(attr)) {
defBuilder.addConstructorArgValue(attr);
}
return defBuilder.getBeanDefinition();
}
@Override
protected boolean shouldGenerateId() {
return true;
}
}

View File

@@ -37,5 +37,7 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("cache-server", new CacheServerParser());
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
}
}

View File

@@ -22,36 +22,36 @@ import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.query.CqQuery;
/**
* Basic holder class for defining an CqQuery. Useful for configuring GemFire {@link CqQuery}s through XML
* Basic holder class for defining an {@link CqQuery}. Useful for configuring GemFire {@link CqQuery}s through XML
* and or JavaBeans means.
*
* @author Costin Leau
*/
public class CqQueryDefinition implements InitializingBean {
public class ContinousQueryDefinition implements InitializingBean {
private String name = null, query = null;
private QueryListener listener = null;
private ContinuousQueryListener listener = null;
private boolean durable = false;
public CqQueryDefinition() {
public ContinousQueryDefinition() {
}
public CqQueryDefinition(String query, QueryListener listener) {
public ContinousQueryDefinition(String query, ContinuousQueryListener listener) {
this(query, listener, false);
}
public CqQueryDefinition(String query, QueryListener listener, boolean durable) {
public ContinousQueryDefinition(String query, ContinuousQueryListener listener, boolean durable) {
this.query = query;
this.listener = listener;
this.durable = durable;
afterPropertiesSet();
}
public CqQueryDefinition(String name, String query, QueryListener listener) {
public ContinousQueryDefinition(String name, String query, ContinuousQueryListener listener) {
this(name, query, listener, false);
}
public CqQueryDefinition(String name, String query, QueryListener listener, boolean durable) {
public ContinousQueryDefinition(String name, String query, ContinuousQueryListener listener, boolean durable) {
this.name = name;
this.query = query;
this.listener = listener;
@@ -81,7 +81,7 @@ public class CqQueryDefinition implements InitializingBean {
/**
* @return the listener
*/
public QueryListener getListener() {
public ContinuousQueryListener getListener() {
return listener;
}

View File

@@ -47,12 +47,12 @@ import com.gemstone.gemfire.internal.concurrent.ConcurrentHashSet;
*
* @author Costin Leau
*/
public class QueryListenerContainer implements InitializingBean, DisposableBean, BeanNameAware, SmartLifecycle {
public class ContinousQueryListenerContainer implements InitializingBean, DisposableBean, BeanNameAware, SmartLifecycle {
private class EventDispatcherAdapter implements CqListener {
private final QueryListener delegate;
private final ContinuousQueryListener delegate;
EventDispatcherAdapter(QueryListener delegate) {
EventDispatcherAdapter(ContinuousQueryListener delegate) {
this.delegate = delegate;
}
@@ -72,9 +72,9 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
protected final Log logger = LogFactory.getLog(getClass());
/**
* Default thread name prefix: "QueryListenerContainer-".
* Default thread name prefix: "ContinousQueryListenerContainer-".
*/
public static final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(QueryListenerContainer.class) + "-";
public static final String DEFAULT_THREAD_NAME_PREFIX = ClassUtils.getShortName(ContinousQueryListenerContainer.class) + "-";
private Executor subscriptionExecutor;
private Executor taskExecutor;
@@ -160,7 +160,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
doStart();
if (logger.isDebugEnabled()) {
logger.debug("Started QueryListenerContainer");
logger.debug("Started ContinousQueryListenerContainer");
}
}
}
@@ -172,7 +172,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
}
if (logger.isDebugEnabled()) {
logger.debug("Stopped QueryListenerContainer");
logger.debug("Stopped ContinousQueryListenerContainer");
}
}
@@ -215,7 +215,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
*
* @see #handleListenerException
*/
protected void executeListener(QueryListener listener, CqEvent event) {
protected void executeListener(ContinuousQueryListener listener, CqEvent event) {
try {
listener.onEvent(event);
} catch (Throwable ex) {
@@ -298,6 +298,11 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
this.queryService = cache.getQueryService();
}
/**
* Set the query service to be used by this container.
*
* @param service query service used by the container
*/
public void setQueryService(QueryService service) {
this.queryService = service;
}
@@ -307,7 +312,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
*
* @param queries set of queries
*/
public void setQueryListeners(Set<CqQueryDefinition> queries) {
public void setQueryListeners(Set<ContinousQueryDefinition> queries) {
initMapping(queries);
}
@@ -317,11 +322,11 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
*
* @param listener event cqQuery
*/
public void addListener(CqQueryDefinition cqQuery) {
public void addListener(ContinousQueryDefinition cqQuery) {
doAddListener(cqQuery);
}
private void initMapping(Set<CqQueryDefinition> queryDefinitions) {
private void initMapping(Set<ContinousQueryDefinition> queryDefinitions) {
// stop the listener if currently running
if (isRunning()) {
stop();
@@ -329,7 +334,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
closeQueries();
for (CqQueryDefinition def : queryDefinitions) {
for (ContinousQueryDefinition def : queryDefinitions) {
doAddListener(def);
}
@@ -339,7 +344,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
}
}
private void doAddListener(CqQueryDefinition def) {
private void doAddListener(ContinousQueryDefinition def) {
CqQuery cq = null;
try {
@@ -375,7 +380,7 @@ public class QueryListenerContainer implements InitializingBean, DisposableBean,
}
}
private void dispatchEvent(final QueryListener listener, final CqEvent event) {
private void dispatchEvent(final ContinuousQueryListener listener, final CqEvent event) {
taskExecutor.execute(new Runnable() {
public void run() {
executeListener(listener, event);

View File

@@ -23,7 +23,7 @@ import com.gemstone.gemfire.cache.query.CqEvent;
*
* @author Costin Leau
*/
public interface QueryListener {
public interface ContinuousQueryListener {
void onEvent(CqEvent event);
}

View File

@@ -17,13 +17,13 @@
package org.springframework.data.gemfire.listener;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.gemfire.listener.adapter.QueryListenerAdapter;
import org.springframework.data.gemfire.listener.adapter.ContinousQueryListenerAdapter;
/**
* Exception thrown when the execution of a listener method failed.
*
* @author Costin Leau
* @see QueryListenerAdapter
* @see ContinousQueryListenerAdapter
*/
public class GemfireListenerExecutionFailedException extends InvalidDataAccessApiUsageException {

View File

@@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.gemfire.listener.GemfireListenerExecutionFailedException;
import org.springframework.data.gemfire.listener.QueryListener;
import org.springframework.data.gemfire.listener.ContinuousQueryListener;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.MethodCallback;
@@ -69,7 +69,7 @@ import com.gemstone.gemfire.cache.query.CqQuery;
* @author Costin Leau
* @see org.springframework.jms.listener.adapter.MessageListenerAdapter
*/
public class QueryListenerAdapter implements QueryListener {
public class ContinousQueryListenerAdapter implements ContinuousQueryListener {
private class MethodInvoker {
private final Object delegate;
@@ -192,18 +192,18 @@ public class QueryListenerAdapter implements QueryListener {
private MethodInvoker invoker;
/**
* Create a new {@link QueryListenerAdapter} with default settings.
* Create a new {@link ContinousQueryListenerAdapter} with default settings.
*/
public QueryListenerAdapter() {
public ContinousQueryListenerAdapter() {
setDelegate(this);
}
/**
* Create a new {@link QueryListenerAdapter} for the given delegate.
* Create a new {@link ContinousQueryListenerAdapter} for the given delegate.
*
* @param delegate the delegate object
*/
public QueryListenerAdapter(Object delegate) {
public ContinousQueryListenerAdapter(Object delegate) {
setDelegate(delegate);
}
@@ -251,7 +251,7 @@ public class QueryListenerAdapter implements QueryListener {
}
/**
* Standard {@link QueryListener} entry point.
* Standard {@link ContinuousQueryListener} entry point.
* <p>Delegates the event to the target listener method, with appropriate
* conversion of the event argument. In case of an exception, the
* {@link #handleListenerException(Throwable)} method will be invoked.
@@ -263,11 +263,11 @@ public class QueryListenerAdapter implements QueryListener {
public void onEvent(CqEvent event) {
try {
// Check whether the delegate is a QueryListener impl itself.
// Check whether the delegate is a ContinuousQueryListener impl itself.
// In that case, the adapter will simply act as a pass-through.
if (delegate != this) {
if (delegate instanceof QueryListener) {
((QueryListener) delegate).onEvent(event);
if (delegate instanceof ContinuousQueryListener) {
((ContinuousQueryListener) delegate).onEvent(event);
}
}

View File

@@ -1032,4 +1032,101 @@ The server groups that this server will be a member of given as a comma separate
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="cq-listener-container">
<xsd:annotation>
<xsd:documentation><![CDATA[
Container for continuous query listeners. All listeners will be hosted by the same container.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="listener" type="listenerType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="cache" type="xsd:string" default="gemfire-cache">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference (by name) to the GemFire cache bean. Default is "gemfire-cache".
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="com.gemstone.gemfire.cache.RegionService"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="task-executor" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference to a Spring TaskExecutor (or standard JDK 1.5 Executor) for executing
GemFire listener invokers. Default is a SimpleAsyncTaskExecutor.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="java.util.concurrent.Executor"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="phase" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The lifecycle phase within which this container should start and stop. The lower
the value the earlier this container will start and the later it will stop. The
default is Integer.MAX_VALUE meaning the container will start as late as possible
and stop as soon as possible.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="listenerType">
<xsd:attribute name="ref" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The bean name of the listener object, implementing the ContinuousQueryListener interface or defining the specified listener method.
Required.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="query" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The query for the GemFire continous query.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="method" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the listener method to invoke. If not specified, the target bean is supposed to implement the ContinuousQueryListener
interface or provide a method named 'handleEvent'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the resulting GemFire continous query. Useful for monitoring and statistics querying.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="durable" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Whether the resulting GemFire continous query is durable or not.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:schema>

View File

@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @author Costin Leau
*/
public class ForkUtil {
private static OutputStream os;
public static OutputStream cloneJVM(String argument) {
String cp = System.getProperty("java.class.path");
@@ -79,6 +80,7 @@ public class ForkUtil {
public void run() {
System.out.println("Stopping fork...");
run.set(false);
os = null;
if (p != null)
p.destroy();
@@ -91,7 +93,8 @@ public class ForkUtil {
}
});
return proc.getOutputStream();
os = proc.getOutputStream();
return os;
}
public static OutputStream cacheServer() {
@@ -103,4 +106,13 @@ public class ForkUtil {
}
return os;
}
public static void sendSignal() {
try {
os.write("\n".getBytes());
os.flush();
} catch (IOException ex) {
throw new IllegalStateException("Cannot communicate with forked VM", ex);
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 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.listener;
import com.gemstone.gemfire.cache.Operation;
import com.gemstone.gemfire.cache.query.CqEvent;
import com.gemstone.gemfire.cache.query.CqQuery;
/**
* Simple GemFire-message/event-driven-pojo.
*
* @author Costin Leau
*/
public class GemfireMDP {
public void handleEvent(CqEvent event) {
System.out.println("Received event " + event);
}
public void handleQuery(CqQuery query) {
System.out.println("Received query " + query);
}
public void handleOperation(Operation op) {
System.out.println("Received operation " + op);
}
}

View File

@@ -16,8 +16,6 @@
package org.springframework.data.gemfire.listener;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
@@ -28,9 +26,10 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.ForkUtil;
import org.springframework.data.gemfire.listener.adapter.QueryListenerAdapter;
import org.springframework.data.gemfire.listener.adapter.ContinousQueryListenerAdapter;
import com.gemstone.gemfire.cache.RegionService;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.cache.client.PoolFactory;
import com.gemstone.gemfire.cache.client.PoolManager;
@@ -42,11 +41,10 @@ import com.gemstone.gemfire.cache.query.CqEvent;
public class ListenerContainerTests {
private final BlockingDeque<CqEvent> bag = new LinkedBlockingDeque<CqEvent>();
protected QueryListenerContainer container;
protected ContinousQueryListenerContainer container;
private static RegionService cache = null;
private static Pool pool = null;
private static OutputStream os = null;
private final Object handler = new Object() {
public void handleEvent(CqEvent event) {
@@ -54,11 +52,11 @@ public class ListenerContainerTests {
}
};
private final QueryListenerAdapter adapter = new QueryListenerAdapter(handler);
private final ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(handler);
@BeforeClass
public static void startUp() throws Exception {
os = ForkUtil.cacheServer();
ForkUtil.cacheServer();
Properties props = new Properties();
props.put("mcast-port", "0");
@@ -73,7 +71,6 @@ public class ListenerContainerTests {
cache = cacheFB.getObject();
PoolFactory pf = PoolManager.createFactory();
pf.addServer("localhost", 40404);
pf.setSubscriptionEnabled(true);
@@ -83,7 +80,7 @@ public class ListenerContainerTests {
@AfterClass
public static void cleanUp() {
sendSignal();
ForkUtil.sendSignal();
if (pool != null) {
pool.destroy();
@@ -101,27 +98,21 @@ public class ListenerContainerTests {
public void setUp() throws Exception {
String query = "SELECT * from /test-cq";
container = new QueryListenerContainer();
container.setQueryService(pool.getQueryService());
container = new ContinousQueryListenerContainer();
//container.setQueryService(pool.getQueryService());
System.out.println(cache instanceof ClientCache);
container.setCache(cache);
container.setBeanName("container");
container.addListener(new CqQueryDefinition("test", query, adapter));
container.addListener(new ContinousQueryDefinition("test", query, adapter));
container.afterPropertiesSet();
}
private static void sendSignal() {
try {
os.write("\n".getBytes());
os.flush();
} catch (IOException ex) {
throw new IllegalStateException("Cannot communicate with forked VM", ex);
}
}
@Test
public void testContainer() throws Exception {
sendSignal();
ForkUtil.sendSignal();
Thread.sleep(3000);
System.out.println("Bag is " + bag);
sendSignal();
ForkUtil.sendSignal();
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 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.listener;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import org.springframework.util.ErrorHandler;
/**
* @author Costin Leau
*/
public class StubErrorHandler implements ErrorHandler {
public BlockingDeque<Throwable> throwables = new LinkedBlockingDeque<Throwable>();
public void handleError(Throwable t) {
throwables.add(t);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 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.listener;
import com.gemstone.gemfire.cache.query.CqEvent;
/**
*
* @author Costin Leau
*/
public class ThrowableEventListener implements ContinuousQueryListener {
public void onEvent(CqEvent event) {
throw new IllegalStateException("throwing exception for event " + event);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 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.listener.adapter;
import static org.junit.Assert.assertTrue;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.data.gemfire.ForkUtil;
import org.springframework.data.gemfire.listener.ContinousQueryListenerContainer;
import com.gemstone.gemfire.cache.Cache;
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.query.CqQuery;
/**
* @author Costin Leau
*/
public class ContainerXmlSetupTest {
@BeforeClass
public static void init() {
ForkUtil.cacheServer();
}
@AfterClass
public static void cleanUp() {
ForkUtil.sendSignal();
}
@Test
public void testContainerSetup() throws Exception {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext(
"/org/springframework/data/gemfire/listener/container.xml");
PoolFactory pf = PoolManager.createFactory();
pf.addServer("localhost", 40404);
pf.setSubscriptionEnabled(true);
Pool pool = pf.create("client");
ContinousQueryListenerContainer container = ctx.getBean(ContinousQueryListenerContainer.class);
assertTrue(container.isRunning());
ForkUtil.sendSignal();
Thread.sleep(3000);
Cache cache = ctx.getBean("gemfire-cache", Cache.class);
CqQuery[] cqs = cache.getQueryService().getCqs();
System.out.println("Cqs " + cqs.length);
ForkUtil.sendSignal();
}
}

View File

@@ -24,7 +24,7 @@ import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.gemfire.listener.QueryListener;
import org.springframework.data.gemfire.listener.ContinuousQueryListener;
import com.gemstone.gemfire.cache.Operation;
import com.gemstone.gemfire.cache.query.CqEvent;
@@ -37,11 +37,11 @@ import com.gemstone.gemfire.cache.query.internal.CqQueryImpl;
*/
public class QueryListenerAdapterTest {
private QueryListenerAdapter adapter;
private ContinousQueryListenerAdapter adapter;
@Before
public void setUp() {
adapter = new QueryListenerAdapter();
adapter = new ContinousQueryListenerAdapter();
}
CqEvent event() {
@@ -113,14 +113,14 @@ public class QueryListenerAdapterTest {
@Test
public void testThatTheDefaultHandlingMethodNameIsTheConstantDefault() throws Exception {
assertEquals(QueryListenerAdapter.ORIGINAL_DEFAULT_LISTENER_METHOD, adapter.getDefaultListenerMethod());
assertEquals(ContinousQueryListenerAdapter.ORIGINAL_DEFAULT_LISTENER_METHOD, adapter.getDefaultListenerMethod());
}
@Test
public void testAdapterWithListenerAndDefaultMessage() throws Exception {
QueryListener mock = mock(QueryListener.class);
ContinuousQueryListener mock = mock(ContinuousQueryListener.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
CqEvent event = event();
adapter.onEvent(event);
verify(mock).onEvent(event);
@@ -129,7 +129,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleEvent() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
CqEvent event = event();
adapter.onEvent(event);
@@ -139,7 +139,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleArray() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleArray");
CqEvent event = event();
adapter.onEvent(event);
@@ -149,7 +149,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleKey() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleKey");
CqEvent event = event();
@@ -160,7 +160,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleKV() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleKV");
CqEvent event = event();
@@ -171,7 +171,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleEx() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleEx");
CqEvent event = event();
@@ -182,7 +182,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleOps() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleOps");
CqEvent event = event();
@@ -193,7 +193,7 @@ public class QueryListenerAdapterTest {
@Test
public void testHandleAll() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleAll");
CqEvent event = event();
@@ -205,7 +205,7 @@ public class QueryListenerAdapterTest {
@Test
public void testInvalid() throws Exception {
Delegate mock = mock(Delegate.class);
QueryListenerAdapter adapter = new QueryListenerAdapter(mock);
ContinousQueryListenerAdapter adapter = new ContinousQueryListenerAdapter(mock);
adapter.setDefaultListenerMethod("handleInvalid");
adapter.onEvent(event());

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:properties id="props">
<prop key="mcast-port">0</prop>
<prop key="name">cq-client</prop>
<prop key="log-level">warning</prop>
</util:properties>
<gfe:cache properties-ref="props" use-bean-factory-locator="false"/>
<gfe:pool id="client" subscription-enabled="true">
<gfe:server host="localhost" port="40404"/>
</gfe:pool>
<task:executor id="testTaskExecutor" />
<gfe:cq-listener-container cache="gemfire-cache">
<!-- default handle method -->
<gfe:listener ref="testBean1" query="SELECT * from /test-cq"/>
<gfe:listener ref="testBean1" query="SELECT * from /test-cq" name="test-bean-1" method="handleQuery"/>
<gfe:listener ref="testBean2" query="SELECT * from /test-cq" durable="false"/>
</gfe:cq-listener-container>
<bean id="testBean1" class="org.springframework.data.gemfire.listener.GemfireMDP"/>
<bean id="testBean2" class="org.springframework.data.gemfire.listener.ThrowableEventListener"/>
<bean id="handler" class="org.springframework.data.gemfire.listener.StubErrorHandler"/>
</beans>