You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2006/12/17 00:58:55 UTC

svn commit: r487919 - in /incubator/openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/ openjpa-kernel/src/main/java/org/apache/openjpa/conf/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/main/java...

Author: pcl
Date: Sat Dec 16 15:58:54 2006
New Revision: 487919

URL: http://svn.apache.org/viewvc?view=rev&rev=487919
Log:
created methods for interacting with product prefixes; moved configuration loading mechanisms to these new methods

Added:
    incubator/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurationProviderPrefixes.java
Modified:
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreBrokerFactory.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerFactoryValue.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAProductDerivation.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
    incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ValueMetaData.java
    incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
    incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java
    incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreBrokerFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreBrokerFactory.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreBrokerFactory.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreBrokerFactory.java Sat Dec 16 15:58:54 2006
@@ -25,6 +25,7 @@
 import org.apache.openjpa.kernel.StoreManager;
 import org.apache.openjpa.lib.conf.ConfigurationProvider;
 import org.apache.openjpa.lib.conf.Configurations;
+import org.apache.openjpa.lib.conf.ProductDerivations;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.util.UserException;
 
@@ -51,8 +52,8 @@
      * The property name under which to name the concrete store manager
      * class for this runtime.
      */
-    public static final String PROP_ABSTRACT_STORE =
-        "org.apache.openjpa.abstractstore.AbstractStoreManager";
+    private static final String PROP_ABSTRACT_STORE =
+        "abstractstore.AbstractStoreManager";
 
     private static final Localizer s_loc = Localizer.forPackage
         (AbstractStoreBrokerFactory.class);
@@ -86,7 +87,8 @@
         // use a tmp store manager to get metadata about the capabilities of
         // this runtime
         Map map = cp.getProperties();
-        String storePlugin = (String) map.get(PROP_ABSTRACT_STORE);
+        String storePlugin = (String) map.get(ProductDerivations
+            .getConfigurationKey(PROP_ABSTRACT_STORE, map));
         String storeCls = Configurations.getClassName(storePlugin);
         String storeProps = Configurations.getProperties(storePlugin);
         AbstractStoreManager store = createStoreManager(storeCls,

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreManager.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/abstractstore/AbstractStoreManager.java Sat Dec 16 15:58:54 2006
@@ -187,7 +187,7 @@
      * Since this store manager does not provide optimistic locking
      * support, this method always returns <code>true</code>.
      */
-    public boolean syncVersion(OpenJPAStateManager sm, Object context) {
+    public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
         return true;
     }
 
@@ -210,7 +210,7 @@
      * data into the object.
      */
     public abstract boolean initialize(OpenJPAStateManager sm, PCState state,
-        FetchConfiguration fetch, Object context);
+        FetchConfiguration fetch, Object edata);
 
     /**
      * This method is invoked when OpenJPA needs to load additional data
@@ -222,7 +222,7 @@
      * data into the object.
      */
     public abstract boolean load(OpenJPAStateManager sm, BitSet fields,
-        FetchConfiguration fetch, int lockLevel, Object context);
+        FetchConfiguration fetch, int lockLevel, Object edata);
 
     /**
      * This implementation just delegates to the proper singular
@@ -232,8 +232,8 @@
      * advantageous.
      */
     public Collection loadAll(Collection sms, PCState state, int load,
-        FetchConfiguration fetch, Object context) {
-        return ImplHelper.loadAll(sms, this, state, load, fetch, context);
+        FetchConfiguration fetch, Object edata) {
+        return ImplHelper.loadAll(sms, this, state, load, fetch, edata);
     }
 
     /**
@@ -362,19 +362,18 @@
      * by <code>subclasses</code>.
      *  The implementation of the result provider will typically execute
      * some sort of data store query to find all the applicable objects, loop
-     * through the returned data, extracting object IDs from the data, and
-     * invoking 
+     * through the results, extracting object IDs from the data, and invoke
      * {@link StoreContext#find(Object,FetchConfiguration,BitSet,Object,int)}
      * on each OID. When invoking this method, the first argument is the OID.
      * The second is the given fetch configuration. The
      * third argument is a mask of fields to exclude from loading; it will
-     * typically be null. The last argument is an object that will be passed
+     * typically be null. The fourth argument is an object that will be passed
      * through to {@link #initialize} or {@link #load}, and typically will
      * contain the actual data to load. For example, for a JDBC-based store
      * manager, this might be the result set that is being iterated over. If
      * this argument is <code>null</code>, then the {@link #initialize} or
      * {@link #load} method will have to issue another command to the data
-     * store in order to fetch the data to be loaded.
+     * store in order to fetch the data to be loaded. 
      */
     public abstract ResultObjectProvider executeExtent(ClassMetaData meta,
         boolean subs, FetchConfiguration fetch);

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerFactoryValue.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerFactoryValue.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerFactoryValue.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/BrokerFactoryValue.java Sat Dec 16 15:58:54 2006
@@ -64,22 +64,17 @@
      * Extract the value of this property if set in the given provider.
      */
     public static Object get(ConfigurationProvider cp) {
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
         Map props = cp.getProperties();
-        Object bf;
-        for (int i = 0; i < prefixes.length; i++) {
-            bf = props.get(prefixes[i] + "." + KEY);
-            if (bf != null)
-                return  bf;
-        }
-        return null;
+        return props.get(ProductDerivations.getConfigurationKey(KEY, props));
     }
 
     /**
      * Set the value of this property in the given provider.
      */
     public static void set(ConfigurationProvider cp, String value) {
-        cp.addProperty("openjpa." + KEY, value);
+        String key = ProductDerivations.getConfigurationKey(KEY, 
+            cp.getProperties());
+        cp.addProperty(key, value);
     }
 
     public BrokerFactoryValue() {

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java Sat Dec 16 15:58:54 2006
@@ -193,10 +193,11 @@
         dataCacheManagerPlugin.setInstantiatingGetter("getDataCacheManager");
 
         dataCachePlugin = addPlugin("DataCache", false);
-        aliases =
-            new String[] { "false", null, "true",
-                ConcurrentDataCache.class.getName(), "concurrent",
-                ConcurrentDataCache.class.getName(), };
+        aliases = new String[] { 
+            "false", null, 
+            "true", ConcurrentDataCache.class.getName(), 
+            "concurrent", ConcurrentDataCache.class.getName(), 
+        };
         dataCachePlugin.setAliases(aliases);
         dataCachePlugin.setDefault(aliases[0]);
         dataCachePlugin.setString(aliases[0]);
@@ -206,10 +207,11 @@
         dataCacheTimeout.set(-1);
 
         queryCachePlugin = addPlugin("QueryCache", true);
-        aliases =
-            new String[] { "true", ConcurrentQueryCache.class.getName(),
-                "concurrent", ConcurrentQueryCache.class.getName(), "false",
-                null, };
+        aliases = new String[] { 
+            "true", ConcurrentQueryCache.class.getName(),
+            "concurrent", ConcurrentQueryCache.class.getName(), 
+            "false", null, 
+        };
         queryCachePlugin.setAliases(aliases);
         queryCachePlugin.setDefault(aliases[0]);
         queryCachePlugin.setString(aliases[0]);

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAProductDerivation.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAProductDerivation.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAProductDerivation.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAProductDerivation.java Sat Dec 16 15:58:54 2006
@@ -33,7 +33,7 @@
 
     /**
      * Load default alias options into the given map.  Each entry maps an
-     * alias to a broker factory class name.  Replace anything perviously 
+     * alias to a broker factory class name.  Replace anything previously 
      * under the desired keys.
      */
     public void putBrokerFactoryAliases(Map aliases);

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java Sat Dec 16 15:58:54 2006
@@ -141,7 +141,7 @@
     /**
      * Load the given state manager.
      * Note that any collection or map types loaded into the state manager
-     * will be proxied with the correct type; therefore the stroe manager
+     * will be proxied with the correct type; therefore the store manager
      * does not have to load the same concrete collection/map types as the
      * instance declares. However, array types must be consistent with the
      * array type stored by the persistence capable instance. If this method

Modified: incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ValueMetaData.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ValueMetaData.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ValueMetaData.java (original)
+++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ValueMetaData.java Sat Dec 16 15:58:54 2006
@@ -296,7 +296,7 @@
 
     /**
      * Copy state from the given value to this one. Do not copy mapping
-      * information.
+     * information.
      */
-    public void copy (ValueMetaData vmd);
+    public void copy(ValueMetaData vmd);
 }

Modified: incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ConfigurationImpl.java Sat Dec 16 15:58:54 2006
@@ -665,27 +665,11 @@
      * Look up the given value, testing all available prefixes.
      */
     private Object get(Map map, Value val, boolean setLoadKey) {
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
-        String firstKey = null;
-        String key;
-        Object o = null;
-        for (int i = 0; i < prefixes.length; i++) {
-            key = prefixes[i] + "." + val.getProperty();
-            if (firstKey == null) {
-                o = map.get(key);
-                if (o != null)
-                    firstKey = key;
-            } else if (map.containsKey(key)) {
-                // if we've already found a property with a previous prefix,
-                // then this is a collision.
-                throw new IllegalStateException(
-                    _loc.get("dup-with-different-prefixes", firstKey, key)
-                        .getMessage());
-            }
-        }
-        if (firstKey != null && setLoadKey)
-            val.setLoadKey(firstKey);
-        return o;
+        String key = ProductDerivations.getConfigurationKey(
+            val.getProperty(), map);
+        if (map.containsKey(key) && setLoadKey)
+            val.setLoadKey(key);
+        return map.get(key);
     }
 
     /**

Modified: incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java Sat Dec 16 15:58:54 2006
@@ -513,30 +513,22 @@
      * configuration prefix.
      */
     public static boolean containsProperty(String key, Map props) {
-        if (key == null || props == null)
+        if (key == null || props == null || props.isEmpty())
             return false;
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
-        for (int i = 0; i < prefixes.length; i++)
-            if (props.containsKey(prefixes[i] + "." + key))
-                return true;
-        return false;
+        else
+            return props.containsKey(
+                ProductDerivations.getConfigurationKey(key, props));
     }
 
     /**
      * Get the property under the given key, prefixed with any possible
      * configuration prefix.
      */
-    public static Object getProperty(String key, Map props) {
-        if (key == null || props == null)
+    public static Object getProperty(String key, Map m) {
+        if (key == null || m == null || m.isEmpty())
             return null;
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
-        Object val;
-        for (int i = 0; i < prefixes.length; i++) {
-            val = props.get(prefixes[i] + "." + key);
-            if (val != null)
-                return val;
-        }
-        return null;
+        else 
+            return m.get(ProductDerivations.getConfigurationKey(key, m));
     }
 
     /**
@@ -544,16 +536,8 @@
      * configuration prefix.
      */
     public static Object removeProperty(String key, Map props) {
-        if (key == null || props == null)
+        if (key == null || props == null || props.isEmpty())
             return null;
-        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
-        Object val = null;
-        Object cur;
-        for (int i = 0; i < prefixes.length; i++) {
-            cur = props.remove(prefixes[i] + "." + key);
-            if (cur != null && val == null)
-                val = cur;
-        }
-        return val;
+        return props.remove(ProductDerivations.getConfigurationKey(key, props));
     }
 }

Modified: incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java?view=diff&rev=487919&r1=487918&r2=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java (original)
+++ incubator/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java Sat Dec 16 15:58:54 2006
@@ -20,6 +20,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.MissingResourceException;
 
 import org.apache.commons.lang.StringUtils;
@@ -40,7 +41,7 @@
     private static final ProductDerivation[] _derivations;
     private static final String[] _derivationNames;
     private static final Throwable[] _derivationErrors;
-    private static final String[] _prefixes;
+    private static String[] _prefixes;
     static {
         ClassLoader l = ProductDerivation.class.getClassLoader();
         _derivationNames = Services.getImplementors(ProductDerivation.class, l);
@@ -85,10 +86,11 @@
                 && !"openjpa".equals(_derivations[i].getConfigurationPrefix()))
                 prefixes.add(_derivations[i].getConfigurationPrefix());
         }
-        _prefixes = new String[1 + prefixes.size()];
-        _prefixes[0] = "openjpa";
+        String[] prefixArray = new String[1 + prefixes.size()];
+        prefixArray[0] = "openjpa";
         for (int i = 0; i < prefixes.size(); i++)
-            _prefixes[i + 1] = (String) prefixes.get(i);
+            prefixArray[i + 1] = (String) prefixes.get(i);
+        setConfigurationPrefixes(prefixArray);
     }
 
     /**
@@ -103,6 +105,50 @@
      */
     public static String[] getConfigurationPrefixes() {
         return _prefixes;
+    }
+
+    /**
+     * Set the configuration prefix array. This is package-visible for 
+     * testing purposes.
+     * 
+     * @since 0.9.7
+     */
+    static void setConfigurationPrefixes(String[] prefixes) {
+        _prefixes = prefixes;
+    }
+    
+    /**
+     * Determine the full key name for <code>key</code>, given the registered
+     * prefixes and the entries in <code>map</code>. This method
+     * computes the appropriate configuration prefix to use by looking 
+     * through <code>map</code> for a key starting with any of the known
+     * configuration prefixes and ending with <code>key</code> and, if a
+     * value is found, using the prefix of that key. Otherwise, it uses
+     * the first registered prefix. 
+     * 
+     * @since 0.9.7
+     */
+    public static String getConfigurationKey(String partialKey, Map map) {
+        String firstKey = null;
+        for (int i = 0; map != null && i < _prefixes.length; i++) {
+            String fullKey = _prefixes[i] + "." + partialKey;
+            if (map.containsKey(fullKey)) {
+                if (firstKey == null) 
+                    firstKey = fullKey;
+                else {
+                    // if we've already found a property with a previous 
+                    // prefix, then this is a collision.
+                    throw new IllegalStateException(_loc.get(
+                        "dup-with-different-prefixes", firstKey, fullKey)
+                        .getMessage());
+                }
+            }
+        }
+        
+        if (firstKey == null)
+            return _prefixes[0] + "." + partialKey;
+        else
+            return firstKey;
     }
 
     /**

Added: incubator/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurationProviderPrefixes.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurationProviderPrefixes.java?view=auto&rev=487919
==============================================================================
--- incubator/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurationProviderPrefixes.java (added)
+++ incubator/openjpa/trunk/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurationProviderPrefixes.java Sat Dec 16 15:58:54 2006
@@ -0,0 +1,85 @@
+package org.apache.openjpa.lib.conf;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+
+public class TestConfigurationProviderPrefixes
+    extends TestCase {
+    
+    private static final String CUSTOM_PREFIX = 
+        TestConfigurationProviderPrefixes.class.getName();
+
+    private String[] _origPrefixes;
+
+    public void setUp() {
+        _origPrefixes = ProductDerivations.getConfigurationPrefixes();
+        List l = new ArrayList(Arrays.asList(_origPrefixes));
+        l.add(CUSTOM_PREFIX);
+        ProductDerivations.setConfigurationPrefixes(
+            (String[]) l.toArray(new String[0]));
+    }
+    
+    public void tearDown() {
+        ProductDerivations.setConfigurationPrefixes(_origPrefixes);
+    }
+    
+    public void testPrefixContents() { 
+        String[] prefixes = ProductDerivations.getConfigurationPrefixes();
+        assertEquals(CUSTOM_PREFIX, prefixes[prefixes.length - 1]);
+        assertEquals("openjpa", prefixes[0]);
+    }
+    
+    public void testPartialKeyAndNullMap() {
+        assertEquals("openjpa.Foo", "Foo", (Map) null, null);
+    }
+        
+    public void testPartialKeyWithInvalidPrefix() {
+        Map map = new HashMap();
+        map.put("bar.Foo", "value");
+        assertEquals("openjpa.Foo", "Foo", map, null);
+    }
+
+    public void testPartialKeyWithoutMatch() {
+        Map map = new HashMap();
+        map.put("bar.Baz", "value");
+        assertEquals("openjpa.Foo", "Foo", map, null);
+    }
+
+    public void testPartialKeyWithOpenJPAMatch() {
+        Map map = new HashMap();
+        map.put("openjpa.Foo", "value");
+        assertEquals("openjpa.Foo", "Foo", map, "value");
+    }
+
+    public void testPartialKeyWithCustomMatch() {
+        Map map = new HashMap();
+        map.put(CUSTOM_PREFIX + ".Foo", "value");
+        assertEquals(CUSTOM_PREFIX + ".Foo", "Foo", map, "value");
+    }
+    
+    public void testPartialKeyDuplicateFullKeys() {
+        Map map = new HashMap();
+        map.put(CUSTOM_PREFIX + ".Foo", "value");
+        map.put("openjpa.Foo", "value");
+        try {
+            ProductDerivations.getConfigurationKey("Foo", map);
+            fail("duplicate keys should result in an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    private static void assertEquals(String fullKey, String partialKey, 
+        Map map, Object value) {
+        assertEquals(fullKey, ProductDerivations.getConfigurationKey(
+            partialKey, map));
+        if (map != null)
+            assertEquals(value, map.get(fullKey));
+    }
+}