OPENJPA-1551:

Storing connectionFactoryName in BrokerImpl - this factory will be used at JDBCStore creation time to override the value from the configuration

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@919557 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Dick 2010-03-05 19:35:53 +00:00
parent a7d613f3bf
commit 4dc0267629
13 changed files with 390 additions and 6 deletions

View File

@ -35,6 +35,7 @@ import java.util.Set;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.event.OrphanedKeyAction;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
@ -43,6 +44,7 @@ import org.apache.openjpa.jdbc.meta.Discriminator;
import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.ValueMapping;
import org.apache.openjpa.jdbc.meta.strats.SuperclassDiscriminatorStrategy;
import org.apache.openjpa.jdbc.schema.DataSourceFactory;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.JoinSyntaxes;
import org.apache.openjpa.jdbc.sql.Joins;
@ -146,15 +148,48 @@ public class JDBCStoreManager
if (lm instanceof JDBCLockManager)
_lm = (JDBCLockManager) lm;
if (!ctx.isManaged() && _conf.isConnectionFactoryModeManaged())
_ds = _conf.getDataSource2(ctx);
else
_ds = _conf.getDataSource(ctx);
_ds = getDataSource(ctx);
if (_conf.getUpdateManagerInstance().orderDirty())
ctx.setOrderDirtyObjects(true);
}
private final boolean useConnectionFactory2(StoreContext ctx) {
return (!ctx.isManaged() && _conf.isConnectionFactoryModeManaged());
}
private final DataSource getDataSource(StoreContext ctx) {
DataSource ds;
if (useConnectionFactory2(ctx)) {
ds = (DataSource) ctx.getConnectionFactory2();
if (ds != null) {
ds = DataSourceFactory.decorateDataSource(ds, _conf, false);
}
else {
ds = _conf.getDataSource2(ctx);
}
} else {
ds = (DataSource) ctx.getConnectionFactory();
if (ds != null) {
ds = DataSourceFactory.decorateDataSource(ds, _conf, false);
}
else {
ds = _conf.getDataSource(ctx);
}
}
return ds;
}
private boolean useContextToGetDataSource(StoreContext ctx) {
// configuration check to enable goes here.
if (StringUtils.isBlank(ctx.getConnectionFactoryName())
&& StringUtils.isBlank(ctx.getConnectionFactory2Name())) {
return false;
}
return true;
}
public JDBCConfiguration getConfiguration() {
return _conf;
}

View File

@ -183,6 +183,11 @@ public abstract class AbstractBrokerFactory
}
public Broker newBroker(String user, String pass, boolean managed, int connRetainMode, boolean findExisting) {
return newBroker(user, pass, managed, connRetainMode, findExisting, "", "");
}
public Broker newBroker(String user, String pass, boolean managed, int connRetainMode, boolean findExisting,
String cf1Name, String cf2Name) {
try {
assertOpen();
makeReadOnly();
@ -192,6 +197,8 @@ public abstract class AbstractBrokerFactory
broker = findBroker(user, pass, managed);
if (broker == null) {
broker = newBrokerImpl(user, pass);
broker.setConnectionFactoryName(cf1Name);
broker.setConnectionFactory2Name(cf2Name);
initializeBroker(managed, connRetainMode, broker, false);
}
return broker;

View File

@ -75,6 +75,29 @@ public interface BrokerFactory
public Broker newBroker(String user, String pass, boolean managed,
int connRetainMode, boolean findExisting);
/**
* Return a new broker using the supplied
* <ul>
* <li>credentials</li>
* <li>transaction management mode</li>
* <li>connectionRetainMode</li>
* <li>connectionFactories</li>
* </ul>
*
* @param user Username to use when obtaining a connection. Will be ignored if a connection factory is
* obtained from JNDI.
* @param pass Password to use when obtaining a connection. Will be ignored if a connection factory is
* obtained from JNDI.
* @param managed Whether managed transactions will be used by this Broker
* @param connRetainMode {@link ConnectionRetainMode}
* @param findExisting Whether the internal pool of brokers should be used.
* @param cfName JTA ConnectionFactory to use
* @param cf2Name Non-JTA ConnectionFactory to use.
* @return A Broker which matches the provided criteria.
*/
public Broker newBroker(String user, String pass, boolean managed,
int connRetainMode, boolean findExisting, String cfName, String cf2Name);
/**
* Register a listener for lifecycle-related events on the specified
* classes. If the classes are null, all events will be propagated to

View File

@ -47,6 +47,7 @@ import org.apache.commons.collections.iterators.IteratorChain;
import org.apache.commons.collections.map.IdentityMap;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.commons.collections.set.MapBackedSet;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.Compatibility;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.datacache.DataCache;
@ -60,6 +61,7 @@ import org.apache.openjpa.event.RemoteCommitEventManager;
import org.apache.openjpa.event.TransactionEvent;
import org.apache.openjpa.event.TransactionEventManager;
import org.apache.openjpa.kernel.exps.ExpressionParser;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
@ -145,6 +147,9 @@ public class BrokerImpl
private static final Object[] EMPTY_OBJECTS = new Object[0];
private String _connectionFactoryName = "";
private String _connectionFactory2Name = "";
private static final Localizer _loc =
Localizer.forPackage(BrokerImpl.class);
@ -4970,4 +4975,60 @@ public class BrokerImpl
public boolean isFromWriteBehindCallback() {
return _fromWriteBehindCallback;
}
/**
* Return the 'JTA' connectionFactoryName
*/
public String getConnectionFactoryName() {
return _connectionFactoryName;
}
/**
* Set the 'JTA' ConnectionFactoryName. Input will be trimmed to null before being stored.
*/
public void setConnectionFactoryName(String connectionFactoryName) {
this._connectionFactoryName = StringUtils.trimToNull(connectionFactoryName);
}
/**
* Return the 'NonJTA' ConnectionFactoryName.
*/
public String getConnectionFactory2Name() {
return _connectionFactory2Name;
}
/**
* Set the 'NonJTA' ConnectionFactoryName. Input will be trimmed to null before being stored.
*/
public void setConnectionFactory2Name(String connectionFactory2Name) {
this._connectionFactory2Name = StringUtils.trimToNull(connectionFactory2Name);
}
/**
* Return the 'JTA' ConnectionFactory, looking it up from JNDI if needed.
*
* @return the JTA connection factory or null if connectionFactoryName is blank.
*/
public Object getConnectionFactory() {
if(StringUtils.isNotBlank(_connectionFactoryName)) {
return Configurations.lookup(_connectionFactoryName, "openjpa.ConnectionFactory", _log );
}
else {
return null;
}
}
/**
* Return the 'NonJTA' ConnectionFactory, looking it up from JNDI if needed.
*
* @return the NonJTA connection factory or null if connectionFactoryName is blank.
*/
public Object getConnectionFactory2() {
if(StringUtils.isNotBlank(_connectionFactory2Name)) {
return Configurations.lookup(_connectionFactory2Name, "openjpa.ConnectionFactory2", _log);
}
else {
return null;
}
}
}

View File

@ -1418,4 +1418,28 @@ public class DelegatingBroker
public void setCachePreparedQuery(boolean flag) {
_broker.setCachePreparedQuery(flag);
}
public String getConnectionFactoryName() {
return _broker.getConnectionFactoryName();
}
public void setConnectionFactoryName(String connectionFactoryName) {
_broker.setConnectionFactoryName(connectionFactoryName);
}
public String getConnectionFactory2Name() {
return _broker.getConnectionFactory2Name();
}
public void setConnectionFactory2Name(String connectionFactory2Name) {
_broker.setConnectionFactory2Name(connectionFactory2Name);
}
public Object getConnectionFactory() {
return _broker.getConnectionFactory();
}
public Object getConnectionFactory2() {
return _broker.getConnectionFactory2();
}
}

View File

@ -148,9 +148,13 @@ public class DelegatingBrokerFactory
public Broker newBroker(String user, String pass, boolean managed,
int connRetainMode, boolean findExisting) {
return newBroker(user, pass, managed, connRetainMode, findExisting, "", "");
}
public Broker newBroker(String user, String pass, boolean managed,
int connRetainMode, boolean findExisting, String cfName, String cf2Name) {
try {
return _factory.newBroker(user, pass, managed, connRetainMode,
findExisting);
findExisting, cfName, cf2Name);
} catch (RuntimeException re) {
throw translate(re);
}

View File

@ -456,4 +456,38 @@ public interface StoreContext {
* Releases the internal lock.
*/
public void unlock ();
/**
* Return the 'JTA' connectionFactoryName
*/
public String getConnectionFactoryName();
/**
* Set the 'JTA' ConnectionFactoryName.
*/
public void setConnectionFactoryName(String connectionFactoryName);
/**
* Return the 'NonJTA' ConnectionFactoryName.
*/
public String getConnectionFactory2Name();
/**
* Set the 'NonJTA' ConnectionFactoryName.
*/
public void setConnectionFactory2Name(String connectionFactory2Name);
/**
* Return the 'JTA' ConnectionFactory, looking it up from JNDI if needed.
*
* @return the JTA connection factory or null if connectionFactoryName is blank.
*/
public Object getConnectionFactory();
/**
* Return the 'NonJTA' ConnectionFactory, looking it up from JNDI if needed.
*
* @return the NonJTA connection factory or null if connectionFactoryName is blank.
*/
public Object getConnectionFactory2();
}

View File

@ -712,6 +712,12 @@
<artifactId>jaxb-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>simple-jndi</groupId>
<artifactId>simple-jndi</artifactId>
<version>0.11.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,55 @@
package org.apache.openjpa.persistence.conf;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
// override defaults to attempt to prevent collisions.
@Entity(name="confPerson")
@Table(name="CONF_PERSON")
public class Person {
@Id
private int id;
@Version
private int version;
@Column(length=16)
private String name;
public Person() {
super();
}
public Person(int id) {
super();
setId(id);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,107 @@
package org.apache.openjpa.persistence.conf;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.RollbackException;
import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
public class TestSwitchConnection extends AbstractPersistenceTestCase {
private String defaultJndiName = "jdbc/mocked";
private String[] jndiNames = { "jdbc/mocked1" };
protected void initEMF(String cfName) {
EntityManagerFactory emf = getEmf("openjpa.ConnectionFactoryName", cfName);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.createQuery("Delete from confPerson").executeUpdate();
em.getTransaction().commit();
em.close();
emf.close();
}
protected EntityManagerFactory getEmf(String cfPropertyName, String cfPropertyValue) {
// null out the driver to prevent system properties from taking effect.
// do not set connectionFactoryModeManaged - or connectionFactory2 will be used.
return createEMF(
"openjpa.ConnectionDriverName", "",
cfPropertyName, cfPropertyValue,
Person.class);
}
protected EntityManager getEm(EntityManagerFactory emf, String name, String value) {
Map<String, Object> props = new HashMap<String, Object>();
props.put(name, value);
return emf.createEntityManager(props);
}
protected void createTables() {
// create an EMF for each database;
initEMF(defaultJndiName);
initEMF(jndiNames[0]);
}
public void testConnectionFactoryName() {
// split out so that we can try javax.persistence.jtaDataSource in the future.
overridePropertyOnEM("openjpa.ConnectionFactoryName", jndiNames[0]);
}
public void overridePropertyOnEM(String name, String value) {
// TODO Disable for non derby.
createTables();
// use the default JndiName for the base EntityManagerFactory
EntityManagerFactory emf = getEmf(name, defaultJndiName);
assertNotNull(emf);
EntityManager em = emf.createEntityManager();
assertNotNull(em);
EntityManager em1 = getEm(emf, name, value);
assertNotNull(em1);
// 'prove' that we're using a different database by inserting the same row
em.getTransaction().begin();
em.persist(new Person(1));
em.getTransaction().commit();
em1.getTransaction().begin();
em1.persist(new Person(1));
em1.getTransaction().commit();
em.clear();
em1.clear();
// sanity test, make sure inserting the same row again fails.
em.getTransaction().begin();
em.persist(new Person(1));
try {
em.getTransaction().commit();
fail("Should not be able to commit the same row a second time");
} catch (RollbackException rbe) {
assertTrue(rbe.getCause() instanceof EntityExistsException);
// expected
}
em1.getTransaction().begin();
em1.persist(new Person(1));
try {
em1.getTransaction().commit();
fail("Should not be able to commit the same row a second time");
} catch (RollbackException rbe) {
assertTrue(rbe.getCause() instanceof EntityExistsException);
// expected
}
em.close();
em1.close();
emf.close();
}
}

View File

@ -0,0 +1,4 @@
java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
org.osjava.sj.root=src/test/resources/simple-jndi
org.osjava.sj.colon.replace=--
org.osjava.sj.delimiter=/

View File

@ -0,0 +1,11 @@
mocked/type=javax.sql.DataSource
mocked/driver=org.apache.derby.jdbc.EmbeddedDriver
mocked/url=jdbc:derby:target/database/jpa-jndi-database;create=true
mocked/user=app
mocked/password=app
mocked1/type=javax.sql.DataSource
mocked1/driver=org.apache.derby.jdbc.EmbeddedDriver
mocked1/url=jdbc:derby:target/database/jpa-jndi-database1;create=true
mocked1/user=app
mocked1/password=app

View File

@ -197,7 +197,20 @@ public class EntityManagerFactoryImpl
}
}
Broker broker = _factory.newBroker(user, pass, managed, retainMode, false);
// javax.persistence.jtaDataSource and openjpa.ConnectionFactory name are equivalent.
// prefer javax.persistence for now.
String cfName = (String) Configurations.removeProperty("jtaDataSource", props);
if(cfName == null) {
cfName = (String) Configurations.removeProperty("ConnectionFactoryName", props);
}
String cf2Name = (String) Configurations.removeProperty("nonJtaDataSource", props);
if(cf2Name == null) {
cf2Name = (String) Configurations.removeProperty("ConnectionFactory2Name", props);
}
Broker broker = _factory.newBroker(user, pass, managed, retainMode, false, cfName, cf2Name);
// add autodetach for close and rollback conditions to the configuration
broker.setAutoDetach(AutoDetach.DETACH_CLOSE, true);