From 6c5887627a057aa48cbad82163f068d344c2aaa7 Mon Sep 17 00:00:00 2001 From: John Blum Date: Wed, 25 Mar 2015 17:06:12 -0700 Subject: [PATCH] SGF-391 - Simplify and improve the robustness of the JNDI DataSource Type matching used in the Cache FactoryBeans. --- .../data/gemfire/CacheFactoryBean.java | 13 ++- .../data/gemfire/JndiDataSourceType.java | 104 ++++++++++++++++++ .../data/gemfire/JndiDataSourceTypeTest.java | 72 ++++++++++++ 3 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/JndiDataSourceType.java create mode 100644 src/test/java/org/springframework/data/gemfire/JndiDataSourceTypeTest.java diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 7f8350e0..3454ad61 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -83,9 +83,6 @@ import com.gemstone.gemfire.pdx.PdxSerializer; public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, BeanNameAware, FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator { - protected static final List VALID_JNDI_DATASOURCE_TYPE_NAMES = Collections.unmodifiableList( - Arrays.asList("ManagedDataSource", "PooledDataSource", "SimpleDataSource", "XAPooledDataSource")); - protected boolean close = true; protected boolean lazyInitialize = true; protected boolean useBeanFactoryLocator = true; @@ -501,9 +498,13 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, private void registerJndiDataSources() { for (JndiDataSource jndiDataSource : nullSafeCollection(jndiDataSources)) { String typeAttributeValue = jndiDataSource.getAttributes().get("type"); - Assert.isTrue(VALID_JNDI_DATASOURCE_TYPE_NAMES.contains(typeAttributeValue), - String.format("'jndi-binding' 'type' [%1$s] is invalid; 'type' must be one of %2$s", - typeAttributeValue, VALID_JNDI_DATASOURCE_TYPE_NAMES)); + JndiDataSourceType jndiDataSourceType = JndiDataSourceType.valueOfIgnoreCase(typeAttributeValue); + + Assert.notNull(jndiDataSourceType, String.format( + "'jndi-binding' 'type' [%1$s] is invalid; 'type' must be one of %2$s", typeAttributeValue, + Arrays.toString(JndiDataSourceType.values()))); + + jndiDataSource.getAttributes().put("type", jndiDataSourceType.getName()); JNDIInvoker.mapDatasource(jndiDataSource.getAttributes(), jndiDataSource.getProps()); } } diff --git a/src/main/java/org/springframework/data/gemfire/JndiDataSourceType.java b/src/main/java/org/springframework/data/gemfire/JndiDataSourceType.java new file mode 100644 index 00000000..7113b1d0 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/JndiDataSourceType.java @@ -0,0 +1,104 @@ +/* + * Copyright 2010-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * The JndiDataSourceType class is an enumeration of valid JNDI DataSource implementation types supported by GemFire. + * + * @author John Blum + * @link http://gemfire.docs.pivotal.io/latest/userguide/index.html#reference/topics/cache_xml.html#jndi-binding + * @since 1.7.0 + */ +@SuppressWarnings("unused") +public enum JndiDataSourceType { + MANAGED("ManagedDataSource"), + POOLED("PooledDataSource"), + SIMPLE("SimpleDataSource"), + XA("XAPooledDataSource"); + + private final String name; + + /** + * Constructs an instance of the JndiDataSourceType enum initialized with the specified name used by GemFire to + * specify supported JNDI DataSource implementations. + * + * @param name the GemFire named JNDI DataSource implementation. + */ + JndiDataSourceType(final String name) { + Assert.hasText(name, "The JNDI DataSource Type 'name' must be specified!"); + this.name = name; + } + + /** + * Returns a JndiDataSourceType enumerated value based on the GemFire preferred name for the supported JNDI, + * DataSource implementation, ignoring case and all extra leading/trailing whitespace. + * + * @param name the GemFire named JNDI DataSource implementation. + * @return the JndiDataSourceType enumerated value matching the given GemFire name used for the supported JNDI, + * DataSource implementation, or null if not match was found. + * @see #values() + * @see #isMatch(JndiDataSourceType, String) + */ + public static JndiDataSourceType valueOfIgnoreCase(final String name) { + for (JndiDataSourceType jndiDataSourceType : values()) { + if (isMatch(jndiDataSourceType, name)) { + return jndiDataSourceType; + } + } + + return null; + } + + /** + * Determines whether the specified JndiDataSourceType enum and the given, supported GemFire 'named', + * JNDI DataSource implementation are a match. + * + * @param jndiDataSourceType the given JndiDataSourceType enum used in the match. + * @param name the specified GemFire "named" JNDI DataSource implementation. + * @return a boolean value indicating whether the given JndiDataSourceType enumerated value matched the given name. + * @see java.lang.String#equalsIgnoreCase(String) + * @see org.springframework.util.StringUtils#trimWhitespace(String) + */ + private static boolean isMatch(final JndiDataSourceType jndiDataSourceType, String name) { + name = StringUtils.trimWhitespace(name); + return (jndiDataSourceType.getName().equalsIgnoreCase(name) + || jndiDataSourceType.name().equalsIgnoreCase(name)); + } + + /** + * Gets the GemFire name of the support JNDI DataSource implementation type. + * + * @return the GemFire named JNDI DataSource implementation. + */ + public String getName() { + return name; + } + + /** + * Returns a String describing this JNDI DataSource implementation based on the GemFire supported names. + * + * @return a String description for this JNDI DataSource (implementation) type. + */ + @Override + public String toString() { + return getName(); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/JndiDataSourceTypeTest.java b/src/test/java/org/springframework/data/gemfire/JndiDataSourceTypeTest.java new file mode 100644 index 00000000..f2f23904 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/JndiDataSourceTypeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +/** + * The JndiDataSourceTypeTest class is a test suite of test cases testing the contract and functionality + * of the JndiDataSourceType enumerated values. + * + * @author John Blum + * @see org.springframework.data.gemfire.JndiDataSourceType + * @since 1.7.0 + */ +public class JndiDataSourceTypeTest { + + @Test + public void testNames() { + assertEquals("ManagedDataSource", JndiDataSourceType.MANAGED.getName()); + assertEquals("PooledDataSource", JndiDataSourceType.POOLED.getName()); + assertEquals("SimpleDataSource", JndiDataSourceType.SIMPLE.getName()); + assertEquals("XAPooledDataSource", JndiDataSourceType.XA.getName()); + } + + @Test + public void testValueOfIgnoreCase() { + assertEquals(JndiDataSourceType.MANAGED, JndiDataSourceType.valueOfIgnoreCase("managedDataSource ")); + assertEquals(JndiDataSourceType.MANAGED, JndiDataSourceType.valueOfIgnoreCase(" ManAGEd")); + assertEquals(JndiDataSourceType.POOLED, JndiDataSourceType.valueOfIgnoreCase("POOLedDataSource")); + assertEquals(JndiDataSourceType.POOLED, JndiDataSourceType.valueOfIgnoreCase("PoolED ")); + assertEquals(JndiDataSourceType.SIMPLE, JndiDataSourceType.valueOfIgnoreCase(" SIMPLEDATASOURCE")); + assertEquals(JndiDataSourceType.SIMPLE, JndiDataSourceType.valueOfIgnoreCase(" SIMPLE ")); + assertEquals(JndiDataSourceType.XA, JndiDataSourceType.valueOfIgnoreCase(" xapooleddatasource ")); + assertEquals(JndiDataSourceType.XA, JndiDataSourceType.valueOfIgnoreCase(" xa ")); + } + + @Test + public void testValueOfIgnoreCaseWithInvalidNames() { + assertNull(JndiDataSourceType.valueOfIgnoreCase("ManageDataSource")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("ManagedDataSink")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("ManedDataSrc")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("PoolingDataSource")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("ComplexDataSource")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("SimplifiedDataSource")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("XA Pooled DataSource")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("X A")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("XADATASOURCE")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("XAPOOLED")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("XA POOLED")); + assertNull(JndiDataSourceType.valueOfIgnoreCase(" ")); + assertNull(JndiDataSourceType.valueOfIgnoreCase("")); + assertNull(JndiDataSourceType.valueOfIgnoreCase(null)); + } + +}