diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java index b3317a508..b256916ff 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java @@ -99,6 +99,41 @@ public class Configurations { return clsName + "(" + props + ")"; } + /** + * Return a plugin string that combines the properties of the given plugin + * strings, where properties of override will override the + * same properties of orig. + */ + public static String combinePlugins(String orig, String override) { + if (StringUtils.isEmpty(orig)) + return override; + if (StringUtils.isEmpty(override)) + return orig; + + String origCls = getClassName(orig); + String overrideCls = getClassName(override); + String cls; + if (StringUtils.isEmpty(origCls)) + cls = overrideCls; + else if (StringUtils.isEmpty(overrideCls)) + cls = origCls; + else if (!origCls.equals(overrideCls)) + return override; // completely different plugin + else + cls = origCls; + + String origProps = getProperties(orig); + String overrideProps = getProperties(override); + if (StringUtils.isEmpty(origProps)) + return getPlugin(cls, overrideProps); + if (StringUtils.isEmpty(overrideProps)) + return getPlugin(cls, origProps); + + Properties props = parseProperties(origProps); + props.putAll(parseProperties(overrideProps)); + return getPlugin(cls, serializeProperties(props)); + } + /** * Create the instance with the given class name, using the given * class loader. No configuration of the instance is performed by diff --git a/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurations.java b/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurations.java index 43bd0e718..f67b40928 100644 --- a/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurations.java +++ b/openjpa-lib/src/test/java/org/apache/openjpa/lib/conf/TestConfigurations.java @@ -12,6 +12,9 @@ */ package org.apache.openjpa.lib.conf; +import java.util.HashMap; +import java.util.Map; + import org.apache.openjpa.lib.test.AbstractTestCase; import org.apache.openjpa.lib.util.Options; @@ -77,6 +80,62 @@ public class TestConfigurations extends AbstractTestCase { assertEquals("baz baz", opts.getProperty("biz")); } + public void testCombinePlugins() { + assertPluginsCombined("jpa", null, + null, null, + "jpa", null); + assertPluginsCombined("jpa", null, + "jpa", null, + "jpa", null); + assertPluginsCombined("jdo", null, + "jpa", null, + "jpa", null); + assertPluginsCombined("jdo", new String[] { "foo", "bar" }, + "jpa", null, + "jpa", null); + assertPluginsCombined("jdo", new String[] { "foo", "bar" }, + "jpa", new String[] { "biz", "baz" }, + "jpa", new String[] { "biz", "baz" }); + assertPluginsCombined("jdo", new String[] { "foo", "bar" }, + null, new String[] { "biz", "baz" }, + "jdo", new String[] { "foo", "bar", "biz", "baz" }); + assertPluginsCombined(null, new String[] { "foo", "bar" }, + null, new String[] { "biz", "baz" }, + null, new String[] { "foo", "bar", "biz", "baz" }); + assertPluginsCombined(null, new String[] { "foo", "bar" }, + "jpa", new String[] { "biz", "baz" }, + "jpa", new String[] { "foo", "bar", "biz", "baz" }); + assertPluginsCombined("jpa", new String[] { "foo", "bar" }, + "jpa", new String[] { "biz", "baz" }, + "jpa", new String[] { "foo", "bar", "biz", "baz" }); + assertPluginsCombined("jpa", new String[] { "foo", "bar" }, + "jpa", new String[] { "foo", "baz" }, + "jpa", new String[] { "foo", "baz" }); + } + + private void assertPluginsCombined(String cls1, String[] props1, + String cls2, String[] props2, String expCls, String[] expProps) { + String plugin1 = Configurations.getPlugin(cls1, + Configurations.serializeProperties(toProperties(props1))); + String plugin2 = Configurations.getPlugin(cls2, + Configurations.serializeProperties(toProperties(props2))); + + String res = Configurations.combinePlugins(plugin1, plugin2); + String resCls = Configurations.getClassName(res); + Map resProps = Configurations.parseProperties(Configurations. + getProperties(res)); + assertEquals(expCls, resCls); + assertEquals(toProperties(expProps), resProps); + } + + private static Map toProperties(String[] props) { + Map map = new HashMap(); + if (props != null) + for (int i = 0; i < props.length; i++) + map.put(props[i], props[++i]); + return map; + } + public static void main(String[] args) { main(TestConfigurations.class); } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java index 04d19de3d..ec67d85a2 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java @@ -32,10 +32,11 @@ import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfigurationImpl; import org.apache.openjpa.conf.OpenJPAProductDerivation; import org.apache.openjpa.lib.conf.AbstractProductDerivation; -import org.apache.openjpa.lib.conf.ProductDerivations; import org.apache.openjpa.lib.conf.Configuration; import org.apache.openjpa.lib.conf.ConfigurationProvider; +import org.apache.openjpa.lib.conf.Configurations; import org.apache.openjpa.lib.conf.MapConfigurationProvider; +import org.apache.openjpa.lib.conf.ProductDerivations; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.meta.XMLMetaDataParser; import org.apache.openjpa.lib.util.Localizer; @@ -382,10 +383,27 @@ public class PersistenceProductDerivation @Override public void setInto(Configuration conf) { - if (conf instanceof OpenJPAConfiguration) - ((OpenJPAConfiguration) conf).setSpecification(SPEC_JPA); - super.setInto(conf, null); + if (conf instanceof OpenJPAConfiguration) { + OpenJPAConfiguration oconf = (OpenJPAConfiguration) conf; + oconf.setSpecification(SPEC_JPA); + // we merge several persistence.xml elements into the + // MetaDataFactory property implicitly. if the user has a + // global openjpa.xml with this property set, its value will + // get overwritten by our implicit setting. so instead, combine + // the global value with our settings + String orig = oconf.getMetaDataFactory(); + if (!StringUtils.isEmpty(orig)) { + String key = ProductDerivations.getConfigurationKey + ("MetaDataFactory", getProperties()); + Object override = getProperties().get(key); + if (override instanceof String) + addProperty(key, Configurations.combinePlugins(orig, + (String) override)); + } + } + + super.setInto(conf, null); Log log = conf.getConfigurationLog(); if (log.isTraceEnabled()) { String src = (_source == null) ? "?" : _source; diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceUnitInfoImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceUnitInfoImpl.java index 901eb01e8..5352a18a5 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceUnitInfoImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceUnitInfoImpl.java @@ -33,6 +33,7 @@ import javax.sql.DataSource; import org.apache.openjpa.lib.conf.Configuration; import org.apache.openjpa.lib.conf.Configurations; +import org.apache.openjpa.lib.conf.ProductDerivations; import org.apache.openjpa.lib.meta.SourceTracker; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.MultiClassLoader; @@ -404,20 +405,14 @@ public class PersistenceUnitInfoImpl } metaFactoryProps.put("Resources", rsrcs.toString()); } + + // set persistent class locations as properties of metadata factory, + // combining them with any existing metadata factory props if (!metaFactoryProps.isEmpty()) { - // set persistent class locations as properties of metadata factory - String factory = (String) Configurations.getProperty + String key = ProductDerivations.getConfigurationKey ("MetaDataFactory", map); - if (factory == null) - factory = Configurations.serializeProperties(metaFactoryProps); - else { - String clsName = Configurations.getClassName(factory); - metaFactoryProps.putAll(Configurations.parseProperties - (Configurations.getProperties(factory))); - factory = Configurations.getPlugin(clsName, - Configurations.serializeProperties(metaFactoryProps)); - } - map.put("openjpa.MetaDataFactory", factory); + map.put(key, Configurations.combinePlugins((String) map.get(key), + Configurations.serializeProperties(metaFactoryProps))); } // always record provider name for product derivations to access