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 d65e9c81..0d131126 100644 --- a/src/main/java/org/springframework/data/gemfire/config/PoolParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/PoolParser.java @@ -31,6 +31,9 @@ import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import com.gemstone.gemfire.cache.server.CacheServer; +import com.gemstone.gemfire.internal.DistributionLocator; + /** * Parser for GFE <pool;gt; bean definitions. * @@ -40,7 +43,18 @@ import org.w3c.dom.Element; */ class PoolParser extends AbstractSimpleBeanDefinitionParser { - @Override + protected static final int DEFAULT_LOCATOR_PORT = DistributionLocator.DEFAULT_LOCATOR_PORT; + protected static final int DEFAULT_SERVER_PORT = CacheServer.DEFAULT_PORT; + + protected static final String DEFAULT_HOST = "localhost"; + protected static final String HOST_ATTRIBUTE_NAME = "host"; + protected static final String LOCATOR_ELEMENT_NAME = "locator"; + protected static final String LOCATORS_ATTRIBUTE_NAME = "locators"; + protected static final String PORT_ATTRIBUTE_NAME = "port"; + protected static final String SERVER_ELEMENT_NAME = "server"; + protected static final String SERVERS_ATTRIBUTE_NAME = "servers"; + + @Override protected Class getBeanClass(Element element) { return PoolFactoryBean.class; } @@ -49,21 +63,24 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser { protected void postProcess(BeanDefinitionBuilder builder, Element element) { List subElements = DomUtils.getChildElements(element); - ManagedList locators = new ManagedList(subElements.size()); - ManagedList servers = new ManagedList(subElements.size()); + ManagedList locators = new ManagedList(subElements.size()); + ManagedList servers = new ManagedList(subElements.size()); // parse nested locator/server elements for (Element subElement : subElements) { String name = subElement.getLocalName(); - if ("locator".equals(name)) { + if (LOCATOR_ELEMENT_NAME.equals(name)) { locators.add(parseLocator(subElement)); } - if ("server".equals(name)) { + if (SERVER_ELEMENT_NAME.equals(name)) { servers.add(parseServer(subElement)); } } + locators.addAll(parseLocators(element)); + servers.addAll(parseServers(element)); + if (!locators.isEmpty()) { builder.addPropertyValue("locators", locators); } @@ -74,24 +91,89 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser { } /* (non-Javadoc) */ - private BeanDefinition parseConnection(Element element) { + BeanDefinition buildConnection(String host, String port, boolean server) { BeanDefinitionBuilder inetSocketAddressBuilder = BeanDefinitionBuilder.genericBeanDefinition( InetSocketAddress.class); - inetSocketAddressBuilder.addConstructorArgValue(element.getAttribute("host")); - inetSocketAddressBuilder.addConstructorArgValue(element.getAttribute("port")); + inetSocketAddressBuilder.addConstructorArgValue(defaultHost(host)); + inetSocketAddressBuilder.addConstructorArgValue(defaultPort(port, server)); return inetSocketAddressBuilder.getBeanDefinition(); } /* (non-Javadoc) */ - private Object parseLocator(Element subElement) { - return parseConnection(subElement); + String defaultHost(String host) { + return (StringUtils.hasText(host) ? host : DEFAULT_HOST); } /* (non-Javadoc) */ - private Object parseServer(Element subElement) { - return parseConnection(subElement); + String defaultPort(String port, boolean server) { + return (StringUtils.hasText(port) ? port : (server ? String.valueOf(DEFAULT_SERVER_PORT) + : String.valueOf(DEFAULT_LOCATOR_PORT))); + } + + /* (non-Javadoc) */ + ManagedList parseConnections(String hostPortCommaDelimitedList, boolean server) { + ManagedList connections = new ManagedList(); + + if (StringUtils.hasText(hostPortCommaDelimitedList)) { + String[] hostPorts = hostPortCommaDelimitedList.split(","); + + for (String hostPort : hostPorts) { + connections.add(parseConnection(hostPort, server)); + } + } + + return connections; + } + + /* (non-Javadoc) */ + BeanDefinition parseConnection(String hostPort, boolean server) { + String port = defaultPort(null, server); + String host; + + int portIndex = hostPort.indexOf('['); + + if (portIndex > -1) { + host = hostPort.substring(0, portIndex).trim(); + port = parseDigits(hostPort.substring(portIndex)).trim(); + } + else { + host = hostPort.trim(); + } + + return buildConnection(host, port, server); + } + + /* (non-Javadoc) */ + String parseDigits(String value) { + StringBuilder digits = new StringBuilder(); + + for (char chr : value.toCharArray()) { + if (Character.isDigit(chr)) { + digits.append(chr); + } + } + + return digits.toString(); + } + + /* (non-Javadoc) */ + BeanDefinition parseLocator(Element element) { + return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME), element.getAttribute(PORT_ATTRIBUTE_NAME), false); + } + + ManagedList parseLocators(Element element) { + return parseConnections(element.getAttribute(LOCATORS_ATTRIBUTE_NAME), false); + } + + /* (non-Javadoc) */ + BeanDefinition parseServer(Element element) { + return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME), element.getAttribute(PORT_ATTRIBUTE_NAME), false); + } + + ManagedList parseServers(Element element) { + return parseConnections(element.getAttribute(SERVERS_ATTRIBUTE_NAME), true); } /* (non-Javadoc) */ diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd index 3b0e60b3..d8bc4fba 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd @@ -2061,46 +2061,43 @@ Note that in order to instantiate a pool, a GemFire cache needs to be already st +The name of the pool definition (by default "gemfirePool"). + ]]> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd index c185705d..291ddd27 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.7.xsd @@ -2061,46 +2061,43 @@ Note that in order to instantiate a pool, a GemFire cache needs to be already st +The name of the pool definition (by default "gemfirePool"). + ]]> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 44493808..052f7425 100644 --- a/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java @@ -39,15 +39,22 @@ import com.gemstone.gemfire.cache.client.PoolManager; /** * @author Costin Leau + * @author John Blum */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="pool-ns.xml", initializers=GemfireTestApplicationContextInitializer.class) @SuppressWarnings("unused") public class PoolNamespaceTest { - + @Autowired private ApplicationContext context; + protected void assertSocketAddress(InetSocketAddress socketAddress, String expectedHost, int expectedPort) { + assertNotNull(socketAddress); + assertEquals(expectedHost, socketAddress.getHostName()); + assertEquals(expectedPort, socketAddress.getPort()); + } + @Test public void testBasicClient() throws Exception { assertTrue(context.containsBean("DEFAULT")); @@ -55,23 +62,20 @@ public class PoolNamespaceTest { assertTrue(context.containsBean("gemfire-pool")); assertEquals(context.getBean("gemfirePool"), PoolManager.find("DEFAULT")); - PoolFactoryBean poolFactoryBean = (PoolFactoryBean) context.getBean("&gemfirePool"); + PoolFactoryBean poolFactoryBean = context.getBean("&gemfirePool", PoolFactoryBean.class); Collection locators = TestUtils.readField("locators", poolFactoryBean); assertNotNull(locators); assertEquals(1, locators.size()); - InetSocketAddress locator = locators.iterator().next(); - - assertEquals("localhost", locator.getHostName()); - assertEquals(40403, locator.getPort()); + assertSocketAddress(locators.iterator().next(), "localhost", 40403); } @Test public void testComplexPool() throws Exception { assertTrue(context.containsBean("complex")); - PoolFactoryBean poolFactoryBean = (PoolFactoryBean) context.getBean("&complex"); + PoolFactoryBean poolFactoryBean = context.getBean("&complex", PoolFactoryBean.class); assertEquals(30, TestUtils.readField("retryAttempts", poolFactoryBean)); assertEquals(6000, TestUtils.readField("freeConnectionTimeout", poolFactoryBean)); @@ -85,16 +89,45 @@ public class PoolNamespaceTest { assertNotNull(servers); assertEquals(2, servers.size()); - Iterator iterator = servers.iterator(); - InetSocketAddress server = iterator.next(); + Iterator serversIterator = servers.iterator(); - assertEquals("localhost", server.getHostName()); - assertEquals(40404, server.getPort()); + assertSocketAddress(serversIterator.next(), "localhost", 40404); + assertSocketAddress(serversIterator.next(), "localhost", 40405); + } - server = iterator.next(); + @Test + public void testComboLocatorPool() throws Exception { + assertTrue(context.containsBean("combo-locators")); - assertEquals("localhost", server.getHostName()); - assertEquals(40405, server.getPort()); + PoolFactoryBean poolFactoryBean = context.getBean("&combo-locators", PoolFactoryBean.class); + Collection locators = TestUtils.readField("locators", poolFactoryBean); + + assertNotNull(locators); + assertEquals(3, locators.size()); + + Iterator locatorIterator = locators.iterator(); + + assertSocketAddress(locatorIterator.next(), "foobar", 55421); + assertSocketAddress(locatorIterator.next(), "lavatube", 11235); + assertSocketAddress(locatorIterator.next(), "zod", 10334); + } + + @Test + public void testComboServerPool() throws Exception { + assertTrue(context.containsBean("combo-servers")); + + PoolFactoryBean poolFactoryBean = context.getBean("&combo-servers", PoolFactoryBean.class); + Collection locators = TestUtils.readField("servers", poolFactoryBean); + + Collection servers = TestUtils.readField("servers", poolFactoryBean); + + assertNotNull(servers); + assertEquals(2, servers.size()); + + Iterator serverIterator = locators.iterator(); + + assertSocketAddress(serverIterator.next(), "scorch", 21480); + assertSocketAddress(serverIterator.next(), "skullbox", 9110); } } diff --git a/src/test/java/org/springframework/data/gemfire/config/PoolParserTest.java b/src/test/java/org/springframework/data/gemfire/config/PoolParserTest.java new file mode 100644 index 00000000..f681cbfb --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/PoolParserTest.java @@ -0,0 +1,252 @@ +/* + * Copyright 2010-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.data.gemfire.client.PoolFactoryBean; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * The PoolParserTest class is a test suite of test cases testing the contract and functionality + * of the PoolParser class. + * + * @author John Blum + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.data.gemfire.config.PoolParser + * @since 1.7.0 + */ +public class PoolParserTest { + + private PoolParser parser = new PoolParser(); + + protected void assertBeanDefinition(BeanDefinition beanDefinition, String expectedHost, String expectedPort) { + assertNotNull(beanDefinition); + assertEquals(2, beanDefinition.getConstructorArgumentValues().getArgumentCount()); + assertEquals(expectedHost, beanDefinition.getConstructorArgumentValues() + .getArgumentValue(0, String.class).getValue()); + assertEquals(expectedPort, beanDefinition.getConstructorArgumentValues() + .getArgumentValue(1, String.class).getValue()); + } + + @Test + public void testGetBeanClass() { + assertEquals(PoolFactoryBean.class, parser.getBeanClass(null)); + } + + @Test + public void testBuildConnection() { + assertBeanDefinition(parser.buildConnection("skullbox", "1234", true), "skullbox", "1234"); + assertBeanDefinition(parser.buildConnection("saturn", " ", true), "saturn", + String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(parser.buildConnection(" ", "", true), PoolParser.DEFAULT_HOST, + String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(parser.buildConnection("neptune", "9876", false), "neptune", "9876"); + assertBeanDefinition(parser.buildConnection("jupiter", null, false), "jupiter", + String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + assertBeanDefinition(parser.buildConnection("", " ", false), PoolParser.DEFAULT_HOST, + String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + } + + @Test + public void testDefaultHost() { + assertEquals("skullbox", parser.defaultHost("skullbox")); + assertEquals("localhost", parser.defaultHost(null)); + assertEquals("localhost", parser.defaultHost("")); + assertEquals("localhost", parser.defaultHost(" ")); + } + + @Test + public void testDefaultPort() { + assertEquals("1234", parser.defaultPort("1234", true)); + assertEquals("9876", parser.defaultPort("9876", false)); + assertEquals(String.valueOf(PoolParser.DEFAULT_SERVER_PORT), parser.defaultPort(null, true)); + assertEquals(String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT), parser.defaultPort("", false)); + assertEquals(String.valueOf(PoolParser.DEFAULT_SERVER_PORT), parser.defaultPort(" ", true)); + } + + @Test + public void testParseConnection() { + assertBeanDefinition(parser.parseConnection("skullbox[1234]", true), "skullbox", "1234"); + assertBeanDefinition(parser.parseConnection("saturn", true), "saturn", + String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(parser.parseConnection("neptune[]", false), "neptune", + String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + assertBeanDefinition(parser.parseConnection("[9876]", true), PoolParser.DEFAULT_HOST, "9876"); + assertBeanDefinition(parser.parseConnection("[]", false), PoolParser.DEFAULT_HOST, + String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + } + + @Test + public void testParseSingleConnection() { + ManagedList beans = parser.parseConnections("skullbox[1234]", true); + + assertNotNull(beans); + assertFalse(beans.isEmpty()); + assertEquals(1, beans.size()); + assertBeanDefinition(beans.get(0), "skullbox", "1234"); + } + + @Test + public void testParseMultipleConnections() { + ManagedList beans = parser.parseConnections( + "skullbox[1234],neptune,saturn[ ],jupiter[SlO], [9876],v3nU5[4_567], localhost [1 01 0] ", true); + + assertNotNull(beans); + assertFalse(beans.isEmpty()); + assertEquals(7, beans.size()); + assertBeanDefinition(beans.get(0), "skullbox", "1234"); + assertBeanDefinition(beans.get(1), "neptune", String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(beans.get(2), "saturn", String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(beans.get(3), "jupiter", String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(beans.get(4), "localhost", "9876"); + assertBeanDefinition(beans.get(5), "v3nU5", "4567"); + assertBeanDefinition(beans.get(6), "localhost", "1010"); + } + + @Test + public void testParseDigits() { + assertEquals("1234", parser.parseDigits("1234")); + assertEquals("4567", parser.parseDigits(" 4567 ")); + assertEquals("78901", parser.parseDigits("7 89 0 1 ")); + assertEquals("8080", parser.parseDigits("[8080]")); + assertEquals("443", parser.parseDigits(":443")); + assertEquals("", parser.parseDigits("")); + assertEquals("", parser.parseDigits(" ")); + assertEquals("", parser.parseDigits("[]")); + assertEquals("", parser.parseDigits("oneTwoThree")); + } + + @Test + public void testParseLocator() { + Element mockElement = mock(Element.class, "testParseLocator.Element"); + + when(mockElement.getAttribute(eq(PoolParser.HOST_ATTRIBUTE_NAME))).thenReturn("skullbox"); + when(mockElement.getAttribute(eq(PoolParser.PORT_ATTRIBUTE_NAME))).thenReturn("1234"); + + assertBeanDefinition(parser.parseLocator(mockElement), "skullbox", "1234"); + } + + @Test + public void testParseLocators() { + Element mockElement = mock(Element.class, "testParseLocators.Element"); + + when(mockElement.getAttribute(eq(PoolParser.LOCATORS_ATTRIBUTE_NAME))).thenReturn("jupiter, saturn[1234]"); + + ManagedList locators = parser.parseLocators(mockElement); + + assertNotNull(locators); + assertFalse(locators.isEmpty()); + assertEquals(2, locators.size()); + assertBeanDefinition(locators.get(0), "jupiter", String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + assertBeanDefinition(locators.get(1), "saturn", "1234"); + } + + @Test + public void testParseServer() { + Element mockElement = mock(Element.class, "testParseServer.Element"); + + when(mockElement.getAttribute(eq(PoolParser.HOST_ATTRIBUTE_NAME))).thenReturn("plato"); + when(mockElement.getAttribute(eq(PoolParser.PORT_ATTRIBUTE_NAME))).thenReturn("9876"); + + assertBeanDefinition(parser.parseServer(mockElement), "plato", "9876"); + } + + @Test + public void testParseServers() { + Element mockElement = mock(Element.class, "testParseServers.Element"); + + when(mockElement.getAttribute(eq(PoolParser.SERVERS_ATTRIBUTE_NAME))).thenReturn(" neptune[], venus[9876]"); + + ManagedList servers = parser.parseServers(mockElement); + + assertNotNull(servers); + assertFalse(servers.isEmpty()); + assertEquals(2, servers.size()); + assertBeanDefinition(servers.get(0), "neptune", String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + assertBeanDefinition(servers.get(1), "venus", "9876"); + } + + @Test + @SuppressWarnings("unchecked") + public void testPostProcess() { + Element mockPoolElement = mock(Element.class, "testPostProcess.MockPoolElement"); + Element mockLocatorOneElement = mock(Element.class, "testPostProcess.MockLocatorOneElement"); + Element mockLocatorTwoElement = mock(Element.class, "testPostProcess.MockLocatorTwoElement"); + Element mockServerElement = mock(Element.class, "testPostProcess.MockServerElement"); + + NodeList mockNodeList = mock(NodeList.class, "testPostProcess.MockNodeList"); + + when(mockPoolElement.getAttribute(PoolParser.LOCATORS_ATTRIBUTE_NAME)).thenReturn("nebula[1122]"); + when(mockPoolElement.getAttribute(PoolParser.SERVERS_ATTRIBUTE_NAME)).thenReturn("skullbox[4848], backspace"); + when(mockPoolElement.getChildNodes()).thenReturn(mockNodeList); + when(mockNodeList.getLength()).thenReturn(3); + when(mockNodeList.item(eq(0))).thenReturn(mockLocatorOneElement); + when(mockNodeList.item(eq(1))).thenReturn(mockServerElement); + when(mockNodeList.item(eq(2))).thenReturn(mockLocatorTwoElement); + when(mockLocatorOneElement.getLocalName()).thenReturn(PoolParser.LOCATOR_ELEMENT_NAME); + when(mockLocatorOneElement.getAttribute(PoolParser.HOST_ATTRIBUTE_NAME)).thenReturn("comet"); + when(mockLocatorOneElement.getAttribute(PoolParser.PORT_ATTRIBUTE_NAME)).thenReturn("1034"); + when(mockLocatorTwoElement.getLocalName()).thenReturn(PoolParser.LOCATOR_ELEMENT_NAME); + when(mockLocatorTwoElement.getAttribute(PoolParser.HOST_ATTRIBUTE_NAME)).thenReturn("quasar"); + when(mockLocatorTwoElement.getAttribute(PoolParser.PORT_ATTRIBUTE_NAME)).thenReturn(" "); + when(mockServerElement.getLocalName()).thenReturn(PoolParser.SERVER_ELEMENT_NAME); + when(mockServerElement.getAttribute(PoolParser.HOST_ATTRIBUTE_NAME)).thenReturn("rightshift"); + when(mockServerElement.getAttribute(PoolParser.PORT_ATTRIBUTE_NAME)).thenReturn("4554"); + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( + parser.getBeanClass(mockPoolElement)); + + parser.postProcess(builder, mockPoolElement); + + BeanDefinition poolDefinition = builder.getRawBeanDefinition(); + + assertNotNull(poolDefinition); + + ManagedList locators = (ManagedList) poolDefinition.getPropertyValues() + .getPropertyValue("locators").getValue(); + + assertNotNull(locators); + assertFalse(locators.isEmpty()); + assertEquals(3, locators.size()); + assertBeanDefinition(locators.get(0), "comet", "1034"); + assertBeanDefinition(locators.get(1), "quasar", String.valueOf(PoolParser.DEFAULT_LOCATOR_PORT)); + assertBeanDefinition(locators.get(2), "nebula", "1122"); + + ManagedList servers = (ManagedList) poolDefinition.getPropertyValues() + .getPropertyValue("servers").getValue(); + + assertNotNull(servers); + assertFalse(servers.isEmpty()); + assertEquals(3, servers.size()); + assertBeanDefinition(servers.get(0), "rightshift", "4554"); + assertBeanDefinition(servers.get(1), "skullbox", "4848"); + assertBeanDefinition(servers.get(2), "backspace", String.valueOf(PoolParser.DEFAULT_SERVER_PORT)); + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml index 0245c853..12080355 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml @@ -14,7 +14,7 @@ PoolNamespaceConfig 0 - warning + error @@ -25,9 +25,18 @@ - + + + + + + + + +