OPENJPA-118: Implemented patch provided by David Ezzio for broken openjpa.AutoDetach behavior

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@502022 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Marc Prud'hommeaux 2007-01-31 22:27:29 +00:00
parent aeafc39d3d
commit 2ac1bcccbb
6 changed files with 253 additions and 7 deletions

View File

@ -15,6 +15,9 @@
*/
package org.apache.openjpa.conf;
import java.util.ArrayList;
import java.util.List;
import org.apache.openjpa.kernel.AutoDetach;
import org.apache.openjpa.lib.conf.StringListValue;
@ -36,13 +39,13 @@ class AutoDetachValue
private static String[] ALIASES = new String[]{
DETACH_CLOSE, String.valueOf(AutoDetach.DETACH_CLOSE),
DETACH_COMMIT, String.valueOf(AutoDetach.DETACH_COMMIT),
DETACH_ROLLBACK, String.valueOf(AutoDetach.DETACH_ROLLBACK),
DETACH_NONTXREAD, String.valueOf(AutoDetach.DETACH_NONTXREAD),
DETACH_ROLLBACK, String.valueOf(AutoDetach.DETACH_ROLLBACK),
// for compatibility with JDO DetachAllOnCommit
"true", String.valueOf(AutoDetach.DETACH_COMMIT),
"false", "0",
};
private int _flags;
private boolean _flagsSet;
@ -70,4 +73,13 @@ class AutoDetachValue
return _flags;
}
protected List getAliasList() {
// We do not document the numeric values and they are not
// helpful to someone trying to understand the error message
ArrayList list = new ArrayList();
for (int x = 0; x < ALIASES.length; x += 2)
list.add(ALIASES[x]);
return list;
}
}

View File

@ -15,6 +15,13 @@
*/
package org.apache.openjpa.lib.conf;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.ParseException;
import serp.util.Strings;
/**
@ -25,6 +32,8 @@ import serp.util.Strings;
public class StringListValue extends Value {
public static final String[] EMPTY = new String[0];
private static final Localizer s_loc = Localizer.forPackage
(StringListValue.class);
private String[] _values = EMPTY;
@ -50,6 +59,61 @@ public class StringListValue extends Value {
public Class getValueType() {
return String[].class;
}
/**
* Unalias the value list. This method defers to super.unalias()
* UNLESS the string passed is a list of values for a property that
* has aliases.
*/
public String unalias(String str) {
// defer to super.unalias
String[] aliases = getAliases();
if (aliases.length <= 0 || str == null)
return super.unalias(str);
str = str.trim();
if (str.length() <= 0)
return super.unalias(str);
// snag this case early as it only causes problems
if (str.equals(","))
throw new ParseException(s_loc.get("invalid-list-config",
getProperty(), str, getAliasList()));
// unalias the list and concatenate the list of
// canonical values. Also, catch any bad aliases.
boolean found;
String iString;
StringBuffer retv = new StringBuffer();
String[] vals = str.split(",", 0);
for (int i = 0; i < vals.length; i++) {
iString = vals[i] = vals[i].trim();
found = false;
if (i > 0)
retv.append(',');
for (int x = 0; x < aliases.length; x += 2)
if (StringUtils.equals(iString, aliases[x])
|| StringUtils.equals(iString, aliases[x + 1])) {
retv.append(aliases[x + 1]);
found = true;
break;
}
// If the alias list is not comprehensive, add any unknown
// values back onto the list
if (!found) {
if (isAliasListComprehensive())
throw new ParseException(s_loc.get("invalid-list-config",
getProperty(), str, getAliasList()));
else
retv.append(iString);
}
}
return retv.toString();
}
protected String getInternalString() {
return Strings.join(_values, ", ");
@ -57,14 +121,21 @@ public class StringListValue extends Value {
protected void setInternalString(String val) {
String[] vals = Strings.split(val, ",", 0);
if (vals != null)
if (vals != null) {
for (int i = 0; i < vals.length; i++)
vals[i] = vals[i].trim();
}
set(vals);
}
protected void setInternalObject(Object obj) {
set((String[]) obj);
}
protected List getAliasList() {
return Arrays.asList(getAliases());
}
}

View File

@ -35,6 +35,10 @@ invalid-config-param-hint: There was an error while setting up the \
invalid-enumerated-config: There was an error while setting up the \
configuration option "{0}", and it was set to "{1}". All \
possible values for this setting are: {2}.
invalid-list-config: There was an error setting up the \
configuration option "{0}". It was set to "{1}". All \
possible values for this setting are: {2}, or a comma separated list \
of the same.
invalid-property-descriptors: Errors occurred while creating property \
descriptors for the following properties: {0}.
invalid-property: The property named "{0}" was not recognized and will \

View File

@ -0,0 +1,76 @@
/*
* Copyright 2006 The Apache Software Foundation.
*
* 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.apache.openjpa.conf;
import java.util.*;
import javax.persistence.*;
import junit.framework.*;
import org.apache.openjpa.kernel.AutoDetach;
import org.apache.openjpa.persistence.*;
public class TestAutoDetachProperty extends TestCase {
private EntityManager em;
private EntityManagerFactory emf;
protected void setUp() throws Exception {
// Don't modify system props, as we are trying to get as close as
// possible to testing props in persistence.xml
HashMap props = new HashMap(System.getProperties());
props.put("openjpa.AutoDetach", "commit,close,nontx-read");
emf = (OpenJPAEntityManagerFactory) Persistence
.createEntityManagerFactory("test", props);
em = emf.createEntityManager();
}
public void tearDown() throws Exception {
em.close();
em = null;
}
public void testIsAutoDetachingOnClose() {
assertTrue("not autodetaching on close as expected",
isAutoDetachingOnClose());
}
public void testIsAutoDetachingOnCommit() {
assertTrue("not autodetaching on commit as expected",
isAutoDetachingOnCommit());
}
public void testIsAutoDetachingOnNonTxRead() {
assertTrue("not autodetaching on nontransactional read as expected",
isAutoDetachingOnNonTxRead());
}
private boolean isAutoDetachingOnClose() {
int autoDetachFlags = OpenJPAPersistence.cast(em).getAutoDetach();
return (autoDetachFlags & AutoDetach.DETACH_CLOSE) > 0;
}
private boolean isAutoDetachingOnCommit() {
int autoDetachFlags = OpenJPAPersistence.cast(em).getAutoDetach();
return (autoDetachFlags & AutoDetach.DETACH_COMMIT) > 0;
}
private boolean isAutoDetachingOnNonTxRead() {
int autoDetachFlags = OpenJPAPersistence.cast(em).getAutoDetach();
return (autoDetachFlags & AutoDetach.DETACH_NONTXREAD) > 0;
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright 2006 The Apache Software Foundation.
*
* 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.apache.openjpa.conf;
import java.util.*;
import javax.persistence.*;
import junit.framework.*;
import org.apache.openjpa.lib.util.ParseException;
import org.apache.openjpa.persistence.*;
import org.apache.openjpa.persistence.PersistenceException;
public class TestBadAutoDetachProperty extends TestCase {
public void testEmptyValue() {
HashMap props = new HashMap(System.getProperties());
props.put("openjpa.AutoDetach", "");
EntityManagerFactory emf = (OpenJPAEntityManagerFactory) Persistence
.createEntityManagerFactory("test", props);
EntityManager em = emf.createEntityManager();
em.close();
emf.close();
}
public void testCommaOnlyValue() {
try {
HashMap props = new HashMap(System.getProperties());
props.put("openjpa.AutoDetach", ",");
EntityManagerFactory emf = (OpenJPAEntityManagerFactory) Persistence
.createEntityManagerFactory("test", props);
EntityManager em = emf.createEntityManager();
em.close();
emf.close();
} catch (PersistenceException e) {
Throwable cause = e.getCause();
if (!(cause instanceof ParseException)) {
fail("Should have caught PersistenceException whose cause was "
+ "a ParseException. " + "Instead the cause was: "
+ cause);
}
} catch (RuntimeException e) {
fail("Should have caught a PersistenceException, instead caught: "
+ e);
}
}
public void testEmptyItemValue() {
try {
HashMap props = new HashMap(System.getProperties());
props.put("openjpa.AutoDetach", "close,,commit");
EntityManagerFactory emf = (OpenJPAEntityManagerFactory) Persistence
.createEntityManagerFactory("test", props);
EntityManager em = emf.createEntityManager();
em.close();
emf.close();
} catch (PersistenceException e) {
Throwable cause = e.getCause();
if (!(cause instanceof ParseException)) {
fail("Should have caught PersistenceException whose cause was "
+ "a ParseException. " + "Instead the cause was: "
+ cause);
}
} catch (RuntimeException e) {
fail("Should have caught a PersistenceException, instead caught: "
+ e);
}
}
}

View File

@ -186,10 +186,11 @@ public class EntityManagerFactoryImpl
Broker broker = _factory.newBroker(user, pass, managed, retainMode,
false);
// we should allow the user to specify these settings in conf
// regardless of PersistenceContextType
broker.setAutoDetach(AutoDetach.DETACH_CLOSE
| AutoDetach.DETACH_ROLLBACK);
// add autodetach for close and rollback conditions to the configuration
broker.setAutoDetach(AutoDetach.DETACH_CLOSE, true);
broker.setAutoDetach(AutoDetach.DETACH_ROLLBACK, true);
broker.setDetachedNew(false);
OpenJPAEntityManager em = newEntityManagerImpl(broker);