Hibernate SVN: r18689 - core/trunk/annotations/src/main/java/org/hibernate/type.
by hibernate-commits@lists.jboss.org
Author: stliu
Date: 2010-02-04 05:57:52 -0500 (Thu, 04 Feb 2010)
New Revision: 18689
Modified:
core/trunk/annotations/src/main/java/org/hibernate/type/EnumType.java
Log:
HHH-4317 Memory leak in EnumType class
Modified: core/trunk/annotations/src/main/java/org/hibernate/type/EnumType.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/type/EnumType.java 2010-02-04 00:07:31 UTC (rev 18688)
+++ core/trunk/annotations/…
[View More]src/main/java/org/hibernate/type/EnumType.java 2010-02-04 10:57:52 UTC (rev 18689)
@@ -23,19 +23,14 @@
*/
package org.hibernate.type;
-import java.io.IOException;
-import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Properties;
-import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.util.StringHelper;
import org.hibernate.usertype.EnhancedUserType;
@@ -51,6 +46,7 @@
* TODO implements readobject/writeobject to recalculate the enumclasses
* @author Emmanuel Bernard
*/
+@SuppressWarnings("unchecked")
public class EnumType implements EnhancedUserType, ParameterizedType, Serializable {
/**
* This is the old scheme where logging of parameter bindings and value extractions
@@ -77,21 +73,17 @@
public static final String COLUMN = "column";
public static final String TYPE = "type";
- private static Map<Class, Object[]> enumValues = new HashMap<Class, Object[]>();
-
private Class<? extends Enum> enumClass;
- private String column;
- private String table;
+ private transient Object[] enumValues;
private String catalog;
private String schema;
- private boolean guessed = false;
private int sqlType = Types.INTEGER; //before any guessing
public int[] sqlTypes() {
return new int[]{sqlType};
}
- public Class returnedClass() {
+ public Class<? extends Enum> returnedClass() {
return enumClass;
}
@@ -103,6 +95,7 @@
return x == null ? 0 : x.hashCode();
}
+
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
Object object = rs.getObject( names[0] );
if ( rs.wasNull() ) {
@@ -112,16 +105,15 @@
return null;
}
if ( object instanceof Number ) {
- Object[] values = enumValues.get( enumClass );
- if ( values == null ) throw new AssertionFailure( "enumValues not preprocessed: " + enumClass );
+ initEnumValues();
int ordinal = ( (Number) object ).intValue();
- if ( ordinal < 0 || ordinal >= values.length ) {
+ if ( ordinal < 0 || ordinal >= enumValues.length ) {
throw new IllegalArgumentException( "Unknown ordinal value for enum " + enumClass + ": " + ordinal );
}
if ( IS_VALUE_TRACING_ENABLED ) {
log().debug( "Returning '{}' as column {}", ordinal, names[0] );
}
- return values[ordinal];
+ return enumValues[ordinal];
}
else {
String name = (String) object;
@@ -146,14 +138,14 @@
else {
boolean isOrdinal = isOrdinal( sqlType );
if ( isOrdinal ) {
- int ordinal = ( (Enum) value ).ordinal();
+ int ordinal = ( (Enum<?>) value ).ordinal();
if ( IS_VALUE_TRACING_ENABLED ) {
log().debug( "Binding '{}' to parameter: {}", ordinal, index );
}
st.setObject( index, Integer.valueOf( ordinal ), sqlType );
}
else {
- String enumString = ( (Enum) value ).name();
+ String enumString = ( (Enum<?>) value ).name();
if ( IS_VALUE_TRACING_ENABLED ) {
log().debug( "Binding '{}' to parameter: {}", enumString, index );
}
@@ -210,30 +202,31 @@
catch (ClassNotFoundException exception) {
throw new HibernateException( "Enum class not found", exception );
}
- //this is threadsafe to do it here, setParameterValues() is called sequencially
- initEnumValue();
+ // is might be good to call it here, to see a possible error immediately
+ // initEnumValue();
+
//nullify unnullified properties yuck!
schema = parameters.getProperty( SCHEMA );
if ( "".equals( schema ) ) schema = null;
catalog = parameters.getProperty( CATALOG );
if ( "".equals( catalog ) ) catalog = null;
- table = parameters.getProperty( TABLE );
- column = parameters.getProperty( COLUMN );
+// table = parameters.getProperty( TABLE );
+// column = parameters.getProperty( COLUMN );
String type = parameters.getProperty( TYPE );
if ( type != null ) {
sqlType = Integer.decode( type ).intValue();
- guessed = true;
+// guessed = true;
}
}
- private void initEnumValue() {
- Object[] values = enumValues.get( enumClass );
- if ( values == null ) {
+ /**
+ * Lazy init of {@link #enumValues}.
+ */
+ private void initEnumValues() {
+ if ( enumValues == null ) {
try {
- Method method = null;
- method = enumClass.getDeclaredMethod( "values", new Class[0] );
- values = (Object[]) method.invoke( null, new Object[0] );
- enumValues.put( enumClass, values );
+ Method method = enumClass.getDeclaredMethod( "values" );
+ enumValues = (Object[]) method.invoke( null );
}
catch (Exception e) {
throw new HibernateException( "Error while accessing enum.values(): " + enumClass, e );
@@ -241,11 +234,11 @@
}
}
- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
- //FIXME Hum, I think I break the thread safety here
- ois.defaultReadObject();
- initEnumValue();
- }
+ // is might be good to call initEnumValues() here, to see a possible error immediatelly, otherwise leave it commented
+// private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+// initEnumValues();
+// ois.defaultReadObject();
+// }
public String objectToSQLString(Object value) {
boolean isOrdinal = isOrdinal( sqlType );
@@ -272,12 +265,11 @@
public Object fromXMLString(String xmlValue) {
try {
int ordinal = Integer.parseInt( xmlValue );
- Object[] values = enumValues.get( enumClass );
- if ( values == null ) throw new AssertionFailure( "enumValues not preprocessed: " + enumClass );
- if ( ordinal < 0 || ordinal >= values.length ) {
+ initEnumValues();
+ if ( ordinal < 0 || ordinal >= enumValues.length ) {
throw new IllegalArgumentException( "Unknown ordinal value for enum " + enumClass + ": " + ordinal );
}
- return values[ordinal];
+ return enumValues[ordinal];
}
catch(NumberFormatException e) {
try {
[View Less]
15 years, 1 month
Hibernate SVN: r18688 - in core/trunk: core/src/main/java/org/hibernate/dialect/lock and 3 other directories.
by hibernate-commits@lists.jboss.org
Author: smarlow(a)redhat.com
Date: 2010-02-03 19:07:31 -0500 (Wed, 03 Feb 2010)
New Revision: 18688
Modified:
core/trunk/core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java
core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java
core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java
core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
core/…
[View More]trunk/core/src/main/java/org/hibernate/sql/SimpleSelect.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
Log:
HHH-4765 Enhance Dialect support for JPA-2 locking. pessimistic no wait/timed locking and additional pessimistic locking tests. Oracle support for pessimistic locking
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -26,6 +26,7 @@
import java.sql.Types;
+import org.hibernate.LockOptions;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.ANSICaseFragment;
@@ -58,9 +59,13 @@
public String getLimitString(String sql, boolean hasOffset) {
sql = sql.trim();
+ String forUpdateClause = null;
boolean isForUpdate = false;
- if ( sql.toLowerCase().endsWith(" for update") ) {
- sql = sql.substring( 0, sql.length()-11 );
+ final int forUpdateIndex = sql.toLowerCase().lastIndexOf( "for update") ;
+ if ( forUpdateIndex > -1 ) {
+ // save 'for update ...' and then remove it
+ forUpdateClause = sql.substring( forUpdateIndex );
+ sql = sql.substring( 0, forUpdateIndex-1 );
isForUpdate = true;
}
@@ -80,7 +85,8 @@
}
if ( isForUpdate ) {
- pagingSelect.append( " for update" );
+ pagingSelect.append( " " );
+ pagingSelect.append( forUpdateClause );
}
return pagingSelect.toString();
@@ -98,4 +104,28 @@
// the standard SQL function name is current_timestamp...
return "current_timestamp";
}
+
+ // locking support
+ public String getForUpdateString() {
+ return " for update";
+ }
+
+ public String getWriteLockString(int timeout) {
+ if ( timeout == LockOptions.NO_WAIT ) {
+ return " for update nowait";
+ }
+ else if ( timeout > 0 ) {
+ // convert from milliseconds to seconds
+ float seconds = timeout / 1000.0f;
+ timeout = Math.round(seconds);
+ return " for update wait " + timeout;
+ }
+ else
+ return " for update";
+ }
+
+ public String getReadLockString(int timeout) {
+ return getWriteLockString( timeout );
+ }
+
}
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticReadSelectLockingStrategy.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -24,6 +24,7 @@
*/
package org.hibernate.dialect.lock;
+import org.hibernate.LockOptions;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SessionFactoryImplementor;
@@ -72,7 +73,7 @@
public PessimisticReadSelectLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable;
this.lockMode = lockMode;
- this.sql = generateLockString();
+ this.sql = generateLockString(LockOptions.WAIT_FOREVER);
}
/**
@@ -83,6 +84,13 @@
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
+ String sql = this.sql;
+ if ( timeout == LockOptions.NO_WAIT ) {
+ sql = generateLockString( LockOptions.NO_WAIT );
+ }
+ else if ( timeout > 0) {
+ sql = generateLockString( timeout );
+ }
SessionFactoryImplementor factory = session.getFactory();
try {
@@ -132,10 +140,12 @@
return lockMode;
}
- protected String generateLockString() {
+ protected String generateLockString(int lockTimeout) {
SessionFactoryImplementor factory = lockable.getFactory();
+ LockOptions lockOptions = new LockOptions(this.lockMode);
+ lockOptions.setTimeOut( lockTimeout );
SimpleSelect select = new SimpleSelect( factory.getDialect() )
- .setLockMode( lockMode )
+ .setLockOptions( lockOptions )
.setTableName( lockable.getRootTableName() )
.addColumn( lockable.getRootTableIdentifierColumnNames()[0] )
.addCondition( lockable.getRootTableIdentifierColumnNames(), "=?" );
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticWriteSelectLockingStrategy.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -24,6 +24,7 @@
*/
package org.hibernate.dialect.lock;
+import org.hibernate.LockOptions;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SessionFactoryImplementor;
@@ -72,7 +73,7 @@
public PessimisticWriteSelectLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable;
this.lockMode = lockMode;
- this.sql = generateLockString();
+ this.sql = generateLockString(LockOptions.WAIT_FOREVER);
}
/**
@@ -83,6 +84,13 @@
Object version,
Object object,
int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
+ String sql = this.sql;
+ if ( timeout == LockOptions.NO_WAIT ) {
+ sql = generateLockString( LockOptions.NO_WAIT );
+ }
+ else if ( timeout > 0) {
+ sql = generateLockString( timeout );
+ }
SessionFactoryImplementor factory = session.getFactory();
try {
@@ -132,10 +140,12 @@
return lockMode;
}
- protected String generateLockString() {
+ protected String generateLockString(int lockTimeout) {
SessionFactoryImplementor factory = lockable.getFactory();
+ LockOptions lockOptions = new LockOptions(this.lockMode);
+ lockOptions.setTimeOut( lockTimeout );
SimpleSelect select = new SimpleSelect( factory.getDialect() )
- .setLockMode( lockMode )
+ .setLockOptions( lockOptions )
.setTableName( lockable.getRootTableName() )
.addColumn( lockable.getRootTableIdentifierColumnNames()[0] )
.addCondition( lockable.getRootTableIdentifierColumnNames(), "=?" );
Modified: core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/AbstractLockUpgradeEventListener.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -107,7 +107,7 @@
entry.forceLocked( object, nextVersion );
}
else {
- persister.lock( entry.getId(), entry.getVersion(), object, requestedLockMode, source );
+ persister.lock( entry.getId(), entry.getVersion(), object, lockOptions, source );
}
entry.setLockMode(requestedLockMode);
}
Modified: core/trunk/core/src/main/java/org/hibernate/sql/SimpleSelect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/sql/SimpleSelect.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/core/src/main/java/org/hibernate/sql/SimpleSelect.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -33,6 +33,7 @@
import java.util.Set;
import org.hibernate.LockMode;
+import org.hibernate.LockOptions;
import org.hibernate.dialect.Dialect;
/**
@@ -51,7 +52,7 @@
private String tableName;
private String orderBy;
private Dialect dialect;
- private LockMode lockMode = LockMode.READ;
+ private LockOptions lockOptions = new LockOptions( LockMode.READ);
private String comment;
private List columns = new ArrayList();
@@ -99,8 +100,13 @@
return this;
}
+ public SimpleSelect setLockOptions( LockOptions lockOptions ) {
+ LockOptions.copy(lockOptions, this.lockOptions);
+ return this;
+ }
+
public SimpleSelect setLockMode(LockMode lockMode) {
- this.lockMode = lockMode;
+ this.lockOptions.setLockMode( lockMode );
return this;
}
@@ -172,7 +178,7 @@
}
buf.append(" from ")
- .append( dialect.appendLockHint(lockMode, tableName) );
+ .append( dialect.appendLockHint(lockOptions.getLockMode(), tableName) );
if ( whereTokens.size() > 0 ) {
buf.append(" where ")
@@ -181,8 +187,8 @@
if (orderBy!=null) buf.append(orderBy);
- if (lockMode!=null) {
- buf.append( dialect.getForUpdateString(lockMode) );
+ if (lockOptions!=null) {
+ buf.append( dialect.getForUpdateString(lockOptions) );
}
return dialect.transformSelectString( buf.toString() );
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-03 21:47:31 UTC (rev 18687)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-04 00:07:31 UTC (rev 18688)
@@ -3,14 +3,22 @@
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
+import javax.persistence.LockTimeoutException;
import javax.persistence.OptimisticLockException;
+import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.ejb.test.TestCase;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
@@ -187,7 +195,7 @@
Lock lock = new Lock();
Thread t = null;
try {
- lock.setName( "contendedLock" );
+ lock.setName( "testContendedPessimisticLock" );
em.getTransaction().begin();
em.persist( lock );
@@ -204,21 +212,24 @@
t = new Thread( new Runnable() {
public void run() {
-
- em2.getTransaction().begin();
- log.info("testContendedPessimisticLock: (BG) about to read write-locked entity");
- // we should block on the following read
- Lock lock2 = em2.getReference( Lock.class, id );
- lock2.getName(); // force entity to be read
- log.info("testContendedPessimisticLock: (BG) read write-locked entity");
- em2.lock( lock2, LockModeType.PESSIMISTIC_READ);
- log.info("testContendedPessimisticLock: (BG) got read lock on entity");
- em2.getTransaction().commit();
- latch.countDown(); // signal that we got the read lock
+ try {
+ em2.getTransaction().begin();
+ log.info("testContendedPessimisticLock: (BG) about to issue (PESSIMISTIC_READ) query against write-locked entity");
+ // we should block on the following read
+ Query query = em2.createQuery(
+ "select L from Lock_ L where L.id < 10000 ");
+ query.setLockMode(LockModeType.PESSIMISTIC_READ);
+ List<Lock> resultList = query.getResultList();
+ resultList.get(0).getName(); // force entity to be read
+ }
+ finally {
+ em2.getTransaction().commit();
+ latch.countDown(); // signal that we got the read lock
+ }
}
} );
- // t.setDaemon( true );
+ t.setDaemon( true );
t.setName("LockTest read lock");
t.start();
log.info("testContendedPessimisticLock: wait on BG thread");
@@ -245,6 +256,263 @@
}
}
+ public void testContendedPessimisticReadLockTimeout() throws Exception {
+
+ EntityManager em = getOrCreateEntityManager();
+ final EntityManager em2 = createIsolatedEntityManager();
+ // TODO: replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
+ if ( ! (getDialect() instanceof Oracle10gDialect)) {
+ log.info("skipping testContendedPessimisticReadLockTimeout");
+ return;
+ }
+ Lock lock = new Lock();
+ Thread t = null;
+ FutureTask<Boolean> bgTask = null;
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ lock.setName( "testContendedPessimisticReadLockTimeout" );
+
+ em.getTransaction().begin();
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.clear();
+
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+ final Integer id = lock.getId();
+ lock.getName(); // force entity to be read
+ log.info("testContendedPessimisticReadLockTimeout: got write lock");
+
+ bgTask = new FutureTask<Boolean>( new Callable() {
+ public Boolean call() {
+ try {
+ boolean timedOut = false; // true (success) if LockTimeoutException occurred
+ em2.getTransaction().begin();
+ log.info("testContendedPessimisticReadLockTimeout: (BG) about to read write-locked entity");
+ // we should block on the following read
+ Lock lock2 = em2.getReference( Lock.class, id );
+ lock2.getName(); // force entity to be read
+ log.info("testContendedPessimisticReadLockTimeout: (BG) read write-locked entity");
+ Map<String,Object> props = new HashMap<String, Object>();
+ // timeout is in milliseconds
+ props.put("javax.persistence.lock.timeout", new Integer(1000));
+ try {
+ em2.lock( lock2, LockModeType.PESSIMISTIC_READ, props);
+ }
+ catch( LockTimeoutException e) {
+ // success
+ log.info("testContendedPessimisticReadLockTimeout: (BG) got expected timeout exception");
+ timedOut = true;
+ }
+ catch ( Throwable e) {
+ log.info("Expected LockTimeoutException but got unexpected exception", e);
+ }
+ em2.getTransaction().commit();
+ return new Boolean(timedOut);
+ }
+ finally {
+ latch.countDown(); // signal that we finished
+ }
+ }
+ } );
+ t = new Thread(bgTask);
+ t.setDaemon( true );
+ t.setName("Lock timeout Test (bg)");
+ t.start();
+ boolean latchSet = latch.await( 10, TimeUnit.SECONDS ); // should return quickly on success
+ assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
+ assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
+ em.getTransaction().commit();
+ }
+ finally {
+ if ( em.getTransaction().isActive() ) {
+ em.getTransaction().rollback();
+ }
+ if ( t != null) { // wait for background thread to finish before deleting entity
+ t.join();
+ }
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.remove( lock );
+ em.getTransaction().commit();
+ em.close();
+ em2.close();
+ }
+ }
+
+ public void testContendedPessimisticWriteLockTimeout() throws Exception {
+
+ EntityManager em = getOrCreateEntityManager();
+ final EntityManager em2 = createIsolatedEntityManager();
+ // TODO: replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
+ if ( ! (getDialect() instanceof Oracle10gDialect)) {
+ log.info("skipping testContendedPessimisticWriteLockTimeout");
+ return;
+ }
+ Lock lock = new Lock();
+ Thread t = null;
+ FutureTask<Boolean> bgTask = null;
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ lock.setName( "testContendedPessimisticWriteLockTimeout" );
+
+ em.getTransaction().begin();
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.clear();
+
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+ final Integer id = lock.getId();
+ lock.getName(); // force entity to be read
+ log.info("testContendedPessimisticWriteLockTimeout: got write lock");
+
+ bgTask = new FutureTask<Boolean>( new Callable() {
+ public Boolean call() {
+ try {
+ boolean timedOut = false; // true (success) if LockTimeoutException occurred
+ em2.getTransaction().begin();
+ log.info("testContendedPessimisticWriteLockTimeout: (BG) about to read write-locked entity");
+ // we should block on the following read
+ Lock lock2 = em2.getReference( Lock.class, id );
+ lock2.getName(); // force entity to be read
+ log.info("testContendedPessimisticWriteLockTimeout: (BG) read write-locked entity");
+ Map<String,Object> props = new HashMap<String, Object>();
+ // timeout is in milliseconds
+ props.put("javax.persistence.lock.timeout", new Integer(1000));
+ try {
+ em2.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props);
+ }
+ catch( LockTimeoutException e) {
+ // success
+ log.info("testContendedPessimisticWriteLockTimeout: (BG) got expected timeout exception");
+ timedOut = true;
+ }
+ catch ( Throwable e) {
+ log.info("Expected LockTimeoutException but got unexpected exception", e);
+ }
+ em2.getTransaction().commit();
+ return new Boolean(timedOut);
+ }
+ finally {
+ latch.countDown(); // signal that we finished
+ }
+ }
+ } );
+ t = new Thread(bgTask);
+ t.setDaemon( true );
+ t.setName("Lock timeout Test (bg)");
+ t.start();
+ boolean latchSet = latch.await( 10, TimeUnit.SECONDS ); // should return quickly on success
+ assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
+ assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
+ em.getTransaction().commit();
+ }
+ finally {
+ if ( em.getTransaction().isActive() ) {
+ em.getTransaction().rollback();
+ }
+ if ( t != null) { // wait for background thread to finish before deleting entity
+ t.join();
+ }
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.remove( lock );
+ em.getTransaction().commit();
+ em.close();
+ em2.close();
+ }
+ }
+
+ public void testContendedPessimisticWriteLockNoWait() throws Exception {
+
+ EntityManager em = getOrCreateEntityManager();
+ final EntityManager em2 = createIsolatedEntityManager();
+ // TODO: replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticLockTimeout)
+ if ( ! (getDialect() instanceof Oracle10gDialect)) {
+ log.info("skipping testContendedPessimisticWriteLockNoWait");
+ return;
+ }
+ Lock lock = new Lock();
+ Thread t = null;
+ FutureTask<Boolean> bgTask = null;
+ final CountDownLatch latch = new CountDownLatch(1);
+ try {
+ lock.setName( "testContendedPessimisticWriteLockNoWait" );
+
+ em.getTransaction().begin();
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.clear();
+
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+ final Integer id = lock.getId();
+ lock.getName(); // force entity to be read
+ log.info("testContendedPessimisticWriteLockNoWait: got write lock");
+
+ bgTask = new FutureTask<Boolean>( new Callable() {
+ public Boolean call() {
+ try {
+ boolean timedOut = false; // true (success) if LockTimeoutException occurred
+ em2.getTransaction().begin();
+ log.info("testContendedPessimisticWriteLockNoWait: (BG) about to read write-locked entity");
+ // we should block on the following read
+ Lock lock2 = em2.getReference( Lock.class, id );
+ lock2.getName(); // force entity to be read
+ log.info("testContendedPessimisticWriteLockNoWait: (BG) read write-locked entity");
+ Map<String,Object> props = new HashMap<String, Object>();
+ // timeout of zero means no wait (for lock)
+ props.put("javax.persistence.lock.timeout", new Integer(0));
+ try {
+ em2.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props);
+ }
+ catch( LockTimeoutException e) {
+ // success
+ log.info("testContendedPessimisticWriteLockNoWait: (BG) got expected timeout exception");
+ timedOut = true;
+ }
+ catch ( Throwable e) {
+ log.info("Expected LockTimeoutException but got unexpected exception", e);
+ }
+ em2.getTransaction().commit();
+ return new Boolean(timedOut);
+ }
+ finally {
+ latch.countDown(); // signal that we finished
+ }
+ }
+ } );
+ t = new Thread(bgTask);
+ t.setDaemon( true );
+ t.setName("Lock timeout Test (bg)");
+ t.start();
+ boolean latchSet = latch.await( 10, TimeUnit.SECONDS ); // should return quickly on success
+ assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
+ assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
+ em.getTransaction().commit();
+ }
+ finally {
+ if ( em.getTransaction().isActive() ) {
+ em.getTransaction().rollback();
+ }
+ if ( t != null) { // wait for background thread to finish before deleting entity
+ t.join();
+ }
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.remove( lock );
+ em.getTransaction().commit();
+ em.close();
+ em2.close();
+ }
+ }
+
+
+
public Class[] getAnnotatedClasses() {
return new Class[]{
Lock.class,
[View Less]
15 years, 1 month
Hibernate SVN: r18687 - in core/trunk: core/src/main/java/org/hibernate/hql/ast/tree and 3 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-02-03 16:47:31 -0500 (Wed, 03 Feb 2010)
New Revision: 18687
Modified:
core/trunk/core/src/main/java/org/hibernate/engine/JoinSequence.java
core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java
core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
core/trunk/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java
core/trunk/testsuite/src/test/java/org/…
[View More]hibernate/test/ternary/TernaryTest.java
Log:
HHH-4879 - Support HQL index-refering functions for many-to-many, indexed collections
Modified: core/trunk/core/src/main/java/org/hibernate/engine/JoinSequence.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/JoinSequence.java 2010-02-03 06:58:46 UTC (rev 18686)
+++ core/trunk/core/src/main/java/org/hibernate/engine/JoinSequence.java 2010-02-03 21:47:31 UTC (rev 18687)
@@ -25,6 +25,7 @@
package org.hibernate.engine;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -66,7 +67,7 @@
return buf.append( '}' ).toString();
}
- final class Join {
+ public final class Join {
private final AssociationType associationType;
private final Joinable joinable;
@@ -83,23 +84,23 @@
this.lhsColumns = lhsColumns;
}
- String getAlias() {
+ public String getAlias() {
return alias;
}
- AssociationType getAssociationType() {
+ public AssociationType getAssociationType() {
return associationType;
}
- Joinable getJoinable() {
+ public Joinable getJoinable() {
return joinable;
}
- int getJoinType() {
+ public int getJoinType() {
return joinType;
}
- String[] getLHSColumns() {
+ public String[] getLHSColumns() {
return lhsColumns;
}
@@ -283,7 +284,15 @@
public int getJoinCount() {
return joins.size();
}
-
+
+ public Iterator iterateJoins() {
+ return joins.iterator();
+ }
+
+ public Join getFirstJoin() {
+ return (Join) joins.get( 0 );
+ }
+
public static interface Selector {
public boolean includeSubclasses(String alias);
}
Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java 2010-02-03 06:58:46 UTC (rev 18686)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromElementType.java 2010-02-03 21:47:31 UTC (rev 18687)
@@ -24,11 +24,15 @@
*/
package org.hibernate.hql.ast.tree;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.param.ParameterSpecification;
+import org.hibernate.persister.collection.CollectionPropertyNames;
+import org.hibernate.type.CollectionType;
import org.hibernate.util.ArrayHelper;
import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.CollectionProperties;
@@ -324,10 +328,16 @@
PropertyMapping propertyMapping = getPropertyMapping( path );
// If this from element is a collection and the path is a collection property (maxIndex, etc.) then
// generate a sub-query.
+ //
+ // NOTE : in the case of this being a collection property in the select, not generating the subquery
+ // will not generally work. The specific cases I am thinking about are the minIndex, maxIndex
+ // (most likely minElement, maxElement as well) cases.
+ // todo : if ^^ is the case we should thrown an exception here rather than waiting for the sql error
+ // if the dialect supports select-clause subqueries we could go ahead and generate the subquery also
if ( !inSelect && queryableCollection != null && CollectionProperties.isCollectionProperty( path ) ) {
Map enabledFilters = fromElement.getWalker().getEnabledFilters();
String subquery = CollectionSubqueryFactory.createCollectionSubquery(
- joinSequence,
+ joinSequence.copy().setUseThetaStyle( true ),
enabledFilters,
propertyMapping.toColumns( tableAlias, path )
);
@@ -397,11 +407,29 @@
return fromElement.getQueryable().getTableName();
}
+ private static final List SPECIAL_MANY2MANY_TREATMENT_FUNCTION_NAMES = java.util.Arrays.asList(
+ new String[] {
+ CollectionPropertyNames.COLLECTION_INDEX,
+ CollectionPropertyNames.COLLECTION_MIN_INDEX,
+ CollectionPropertyNames.COLLECTION_MAX_INDEX
+ }
+ );
+
PropertyMapping getPropertyMapping(String propertyName) {
checkInitialized();
if ( queryableCollection == null ) { // Not a collection?
return ( PropertyMapping ) persister; // Return the entity property mapping.
}
+
+ // indexed, many-to-many collections must be treated specially here if the property to
+ // be mapped touches on the index as we must adjust the alias to use the alias from
+ // the association table (which i different than the one passed in
+ if ( queryableCollection.isManyToMany()
+ && queryableCollection.hasIndex()
+ && SPECIAL_MANY2MANY_TREATMENT_FUNCTION_NAMES.contains( propertyName ) ) {
+ return new SpecialManyToManyCollectionPropertyMapping();
+ }
+
// If the property is a special collection property name, return a CollectionPropertyMapping.
if ( CollectionProperties.isCollectionProperty( propertyName ) ) {
if ( collectionPropertyMapping == null ) {
@@ -409,12 +437,14 @@
}
return collectionPropertyMapping;
}
+
if ( queryableCollection.getElementType().isAnyType() ) {
// collection of <many-to-any/> mappings...
// used to circumvent the component-collection check below...
return queryableCollection;
}
+
if ( queryableCollection.getElementType().isComponentType() ) {
// Collection of components.
if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) {
@@ -425,17 +455,9 @@
}
public boolean isCollectionOfValuesOrComponents() {
- if ( persister == null ) {
- if ( queryableCollection == null ) {
- return false;
- }
- else {
- return !queryableCollection.getElementType().isEntityType();
- }
- }
- else {
- return false;
- }
+ return persister == null
+ && queryableCollection != null
+ && !queryableCollection.getElementType().isEntityType();
}
public boolean isEntity() {
@@ -449,4 +471,62 @@
public void setIndexCollectionSelectorParamSpec(ParameterSpecification indexCollectionSelectorParamSpec) {
this.indexCollectionSelectorParamSpec = indexCollectionSelectorParamSpec;
}
+
+ private class SpecialManyToManyCollectionPropertyMapping implements PropertyMapping {
+ /**
+ * {@inheritDoc}
+ */
+ public Type getType() {
+ return queryableCollection.getCollectionType();
+ }
+
+ private void validate(String propertyName) {
+ if ( ! ( CollectionPropertyNames.COLLECTION_INDEX.equals( propertyName )
+ || CollectionPropertyNames.COLLECTION_MAX_INDEX.equals( propertyName )
+ || CollectionPropertyNames.COLLECTION_MIN_INDEX.equals( propertyName ) ) ) {
+ throw new IllegalArgumentException( "Expecting index-related function call" );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Type toType(String propertyName) throws QueryException {
+ validate( propertyName );
+ return queryableCollection.getIndexType();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
+ validate( propertyName );
+ final String joinTableAlias = joinSequence.getFirstJoin().getAlias();
+ if ( CollectionPropertyNames.COLLECTION_INDEX.equals( propertyName ) ) {
+ return queryableCollection.toColumns( joinTableAlias, propertyName );
+ }
+
+ final String[] cols = queryableCollection.getIndexColumnNames( joinTableAlias );
+ if ( CollectionPropertyNames.COLLECTION_MIN_INDEX.equals( propertyName ) ) {
+ if ( cols.length != 1 ) {
+ throw new QueryException( "composite collection index in minIndex()" );
+ }
+ return new String[] { "min(" + cols[0] + ')' };
+ }
+ else {
+ if ( cols.length != 1 ) {
+ throw new QueryException( "composite collection index in maxIndex()" );
+ }
+ return new String[] { "max(" + cols[0] + ')' };
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException {
+ validate( propertyName );
+ return queryableCollection.toColumns( propertyName );
+ }
+ }
}
Modified: core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java 2010-02-03 06:58:46 UTC (rev 18686)
+++ core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java 2010-02-03 21:47:31 UTC (rev 18687)
@@ -1510,27 +1510,33 @@
return buffer.toString();
}
- public String[] toColumns(String alias, String propertyName)
- throws QueryException {
-
+ /**
+ * {@inheritDoc}
+ */
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
if ( "index".equals( propertyName ) ) {
- if ( isManyToMany() ) {
- throw new QueryException( "index() function not supported for many-to-many association" );
- }
- return StringHelper.qualify( alias, indexColumnNames );
+ return qualify( alias, indexColumnNames, indexFormulaTemplates );
}
-
return elementPropertyMapping.toColumns( alias, propertyName );
}
- public String[] toColumns(String propertyName)
- throws QueryException {
+ private String[] indexFragments;
+ /**
+ * {@inheritDoc}
+ */
+ public String[] toColumns(String propertyName) throws QueryException {
if ( "index".equals( propertyName ) ) {
- if ( isManyToMany() ) {
- throw new QueryException( "index() function not supported for many-to-many association" );
+ if ( indexFragments == null ) {
+ String[] tmp = new String[indexColumnNames.length];
+ for ( int i = 0; i < indexColumnNames.length; i++ ) {
+ tmp[i] = indexColumnNames[i] == null
+ ? indexFormulas[i]
+ : indexColumnNames[i];
+ indexFragments = tmp;
+ }
}
- return indexColumnNames;
+ return indexFragments;
}
return elementPropertyMapping.toColumns( propertyName );
Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java 2010-02-03 06:58:46 UTC (rev 18686)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/map/MapIndexFormulaTest.java 2010-02-03 21:47:31 UTC (rev 18687)
@@ -27,7 +27,20 @@
public static Test suite() {
return new FunctionalTestClassTestSuite( MapIndexFormulaTest.class );
}
-
+
+ public void testIndexFunctionOnManyToManyMap() {
+ Session s = openSession();
+ s.beginTransaction();
+ s.createQuery( "from Group g join g.users u where g.name = 'something' and index(u) = 'nada'" )
+ .list();
+ s.createQuery( "from Group g join g.users u where g.name = 'something' and minindex(u) = 'nada'" )
+ .list();
+ s.createQuery( "from Group g join g.users u where g.name = 'something' and maxindex(u) = 'nada'" )
+ .list();
+ s.getTransaction().commit();
+ s.close();
+ }
+
public void testIndexFormulaMap() {
Session s = openSession();
Transaction t = s.beginTransaction();
Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java 2010-02-03 06:58:46 UTC (rev 18686)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/ternary/TernaryTest.java 2010-02-03 21:47:31 UTC (rev 18687)
@@ -112,5 +112,17 @@
s.close();
}
+ public void testIndexRelatedFunctions() {
+ Session session = openSession();
+ session.beginTransaction();
+ session.createQuery( "from Employee e join e.managerBySite as m where index(m) is not null" )
+ .list();
+ session.createQuery( "from Employee e join e.managerBySite as m where minIndex(m) is not null" )
+ .list();
+ session.createQuery( "from Employee e join e.managerBySite as m where maxIndex(m) is not null" )
+ .list();
+ session.getTransaction().commit();
+ session.close();
+ }
}
[View Less]
15 years, 1 month
Hibernate SVN: r18686 - in core/trunk: core/src/main/java/org/hibernate/event/def and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-02-03 01:58:46 -0500 (Wed, 03 Feb 2010)
New Revision: 18686
Modified:
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/FinancialHistory.java
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java
core/…
[View More]trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
Log:
HHH-4861 - Allow lookup by the "simple" pk type of "parent entity" in "derived identities" cases
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java 2010-02-03 06:51:48 UTC (rev 18685)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/DerivedIdentitySimpleParentSimpleDepTest.java 2010-02-03 06:58:46 UTC (rev 18686)
@@ -14,56 +14,80 @@
public void testOneToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "MedicalHistory", "FK", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "MedicalHistory", "id", getCfg() ) );
- Person e = new Person();
- e.ssn = "aaa";
- Session s = openSession( );
+
+ Session s = openSession();
s.getTransaction().begin();
- s.persist( e );
- MedicalHistory d = new MedicalHistory();
- d.patient = e;
- s.persist( d );
- s.flush();
- s.clear();
- final Class<MedicalHistory> clazz = MedicalHistory.class;
- d = getDerivedClassById( e, s, clazz );
- assertEquals( e.ssn, d.patient.ssn );
- d.lastupdate = new Date();
- s.flush();
- s.clear();
- d = getDerivedClassById( e, s, clazz );
- assertNotNull( d.lastupdate );
- s.getTransaction().rollback();
+ Person person = new Person( "aaa" );
+ s.persist( person );
+ MedicalHistory medicalHistory = new MedicalHistory( person );
+ s.persist( medicalHistory );
+ s.getTransaction().commit();
s.close();
- }
- private <T> T getDerivedClassById(Person e, Session s, Class<T> clazz) {
- return ( T )
- s.createQuery( "from " + clazz.getName() + " mh where mh.patient.ssn = :ssn")
- .setParameter( "ssn", e.ssn ).uniqueResult();
+ s = openSession();
+ s.getTransaction().begin();
+ medicalHistory = (MedicalHistory) s.get( MedicalHistory.class, "aaa" );
+ assertEquals( person.ssn, medicalHistory.patient.ssn );
+ medicalHistory.lastupdate = new Date();
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.getTransaction().begin();
+ medicalHistory = (MedicalHistory) s.get( MedicalHistory.class, "aaa" );
+ assertNotNull( medicalHistory.lastupdate );
+ s.delete( medicalHistory );
+ s.getTransaction().commit();
+ s.close();
}
public void testManyToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "FinancialHistory", "patient_ssn", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "FinancialHistory", "id", getCfg() ) );
- Person e = new Person();
- e.ssn = "aaa";
- Session s = openSession( );
+
+ Session s = openSession();
s.getTransaction().begin();
+ Person person = new Person( "aaa" );
+ s.persist( person );
+ FinancialHistory financialHistory = new FinancialHistory( person );
+ s.persist( financialHistory );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.getTransaction().begin();
+ financialHistory = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
+ assertEquals( person.ssn, financialHistory.patient.ssn );
+ financialHistory.lastUpdate = new Date();
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.getTransaction().begin();
+ financialHistory = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
+ assertNotNull( financialHistory.lastUpdate );
+ s.delete( financialHistory );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testSimplePkValueLoading() {
+ Session s = openSession();
+ s.getTransaction().begin();
+ Person e = new Person( "aaa" );
s.persist( e );
- FinancialHistory d = new FinancialHistory();
- d.patient = e;
+ FinancialHistory d = new FinancialHistory( e );
s.persist( d );
- s.flush();
- s.clear();
- d = getDerivedClassById(e, s, FinancialHistory.class);
- assertEquals( e.ssn, d.patient.ssn );
- d.lastupdate = new Date();
- s.flush();
- s.clear();
- d = getDerivedClassById(e, s, FinancialHistory.class);
- assertNotNull( d.lastupdate );
- s.getTransaction().rollback();
+ s.getTransaction().commit();
s.close();
+
+ s = openSession();
+ s.getTransaction().begin();
+ FinancialHistory history = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
+ assertNotNull( history );
+ s.delete( history );
+ s.getTransaction().commit();
+ s.close();
}
@Override
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/FinancialHistory.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/FinancialHistory.java 2010-02-03 06:51:48 UTC (rev 18685)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/FinancialHistory.java 2010-02-03 06:58:46 UTC (rev 18686)
@@ -16,13 +16,18 @@
*/
@Entity
public class FinancialHistory implements Serializable {
-
- @Temporal(TemporalType.DATE)
- Date lastupdate;
-
@Id
//@JoinColumn(name = "FK")
@ManyToOne
Person patient;
+ @Temporal(TemporalType.DATE)
+ Date lastUpdate;
+
+ public FinancialHistory() {
+ }
+
+ public FinancialHistory(Person patient) {
+ this.patient = patient;
+ }
}
\ No newline at end of file
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java 2010-02-03 06:51:48 UTC (rev 18685)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/MedicalHistory.java 2010-02-03 06:58:46 UTC (rev 18686)
@@ -16,12 +16,18 @@
*/
@Entity
public class MedicalHistory implements Serializable {
+ @Id
+ @JoinColumn(name = "FK")
+ @OneToOne
+ Person patient;
@Temporal(TemporalType.DATE)
Date lastupdate;
- @Id
- @JoinColumn(name = "FK")
- @OneToOne
- Person patient;
+ public MedicalHistory() {
+ }
+
+ public MedicalHistory(Person patient) {
+ this.patient = patient;
+ }
}
\ No newline at end of file
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java 2010-02-03 06:51:48 UTC (rev 18685)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/a/Person.java 2010-02-03 06:58:46 UTC (rev 18686)
@@ -11,4 +11,11 @@
public class Person {
@Id
String ssn;
+
+ public Person() {
+ }
+
+ public Person(String ssn) {
+ this.ssn = ssn;
+ }
}
\ No newline at end of file
Modified: core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java 2010-02-03 06:51:48 UTC (rev 18685)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/DefaultLoadEventListener.java 2010-02-03 06:58:46 UTC (rev 18686)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.event.def;
@@ -54,6 +53,8 @@
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.type.EmbeddedComponentType;
+import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
@@ -106,6 +107,31 @@
else {
Class idClass = persister.getIdentifierType().getReturnedClass();
if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {
+ // we may have the kooky jpa requirement of allowing find-by-id where
+ // "id" is the "simple pk value" of a dependent objects parent. This
+ // is part of its generally goofy "derived identity" "feature"
+ if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
+ final EmbeddedComponentType dependentIdType =
+ (EmbeddedComponentType) persister.getEntityMetamodel().getIdentifierProperty().getType();
+ if ( dependentIdType.getSubtypes().length == 1 ) {
+ final Type singleSubType = dependentIdType.getSubtypes()[0];
+ if ( singleSubType.isEntityType() ) {
+ final EntityType dependentParentType = (EntityType) singleSubType;
+ final Type dependentParentIdType = dependentParentType.getIdentifierOrUniqueKeyType( source.getFactory() );
+ if ( dependentParentIdType.getReturnedClass().isInstance( event.getEntityId() ) ) {
+ // yep that's what we have...
+ loadByDerivedIdentitySimplePkValue(
+ event,
+ loadType,
+ persister,
+ dependentIdType,
+ source.getFactory().getEntityPersister( dependentParentType.getAssociatedEntityName() )
+ );
+ return;
+ }
+ }
+ }
+ }
throw new TypeMismatchException(
"Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass + ", got " + event.getEntityId().getClass()
);
@@ -136,6 +162,42 @@
}
}
+ private void loadByDerivedIdentitySimplePkValue(
+ LoadEvent event,
+ LoadEventListener.LoadType options,
+ EntityPersister dependentPersister,
+ EmbeddedComponentType dependentIdType,
+ EntityPersister parentPersister) {
+ final EntityKey parentEntityKey = new EntityKey(
+ event.getEntityId(),
+ parentPersister,
+ event.getSession().getEntityMode()
+ );
+ final Object parent = doLoad(
+ event,
+ parentPersister,
+ parentEntityKey,
+ options
+ );
+
+ Serializable dependent = (Serializable) dependentIdType.instantiate( parent, event.getSession() );
+ dependentIdType.setPropertyValues( dependent, new Object[] {parent}, event.getSession().getEntityMode() );
+ final EntityKey dependentEntityKey = new EntityKey(
+ dependent,
+ dependentPersister,
+ event.getSession().getEntityMode()
+ );
+ event.setEntityId( dependent );
+ dependent = (Serializable) doLoad(
+ event,
+ dependentPersister,
+ dependentEntityKey,
+ options
+ );
+
+ event.setResult( dependent );
+ }
+
/**
* Perfoms the load of an entity.
*
[View Less]
15 years, 1 month
Hibernate SVN: r18685 - core/trunk/documentation/manual/src/main/docbook/en-US/content.
by hibernate-commits@lists.jboss.org
Author: stliu
Date: 2010-02-03 01:51:48 -0500 (Wed, 03 Feb 2010)
New Revision: 18685
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/best_practices.xml
Log:
HHH-4824 localpath appeared in the doc xml
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/best_practices.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/best_practices.xml 2010-02-03 05:16:26 UTC …
[View More](rev 18684)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/best_practices.xml 2010-02-03 06:51:48 UTC (rev 18685)
@@ -125,7 +125,7 @@
In performance-critical areas of the system, some kinds of operations might benefit from
direct JDBC. Do not assume, however, that JDBC is necessarily faster. Please wait until you <emphasis>know</emphasis> something is a bottleneck.
If you need to use direct JDBC,
- you can open a Hibernate <literal>Session</literal> and usingfile:///usr/share/doc/HTML/en-US/index.html that JDBC connection. This
+ you can open a Hibernate <literal>Session</literal>, wrap your JDBC operation as a <literal>org.hibernate.jdbc.Work</literal> object and using that JDBC connection. This
way you can still use the same transaction strategy and underlying connection provider.
</para>
</listitem>
[View Less]
15 years, 1 month
Hibernate SVN: r18684 - in core/trunk: entitymanager/src/main/java/org/hibernate/ejb and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-02-03 00:16:26 -0500 (Wed, 03 Feb 2010)
New Revision: 18684
Added:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java
Modified:
core/trunk/core/src/main/java/org/hibernate/engine/ActionQueue.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
core/trunk/entitymanager/src/test/java/org/…
[View More]hibernate/ejb/test/lock/QueryLockingTest.java
Log:
HHH-4661 - Properly propagate Query.setLockMode to Hibernate Core
Modified: core/trunk/core/src/main/java/org/hibernate/engine/ActionQueue.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/ActionQueue.java 2010-02-02 21:51:40 UTC (rev 18683)
+++ core/trunk/core/src/main/java/org/hibernate/engine/ActionQueue.java 2010-02-03 05:16:26 UTC (rev 18684)
@@ -375,10 +375,13 @@
}
public boolean hasAfterTransactionActions() {
- // todo : method is not used anywhere; why is it here?
return afterTransactionProcesses.processes.size() > 0;
}
+ public boolean hasBeforeTransactionActions() {
+ return beforeTransactionProcesses.processes.size() > 0;
+ }
+
public boolean hasAnyQueuedActions() {
return updates.size() > 0 ||
insertions.size() > 0 ||
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-02 21:51:40 UTC (rev 18683)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java 2010-02-03 05:16:26 UTC (rev 18684)
@@ -35,6 +35,7 @@
import java.util.Map;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
+import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
@@ -895,16 +896,16 @@
}
public <T> T unwrap(Class<T> clazz) {
- if ( clazz.equals( Session.class ) ) {
+ if ( Session.class.isAssignableFrom( clazz ) ) {
return ( T ) getSession();
}
- if ( clazz.equals( SessionImplementor.class ) ) {
+ if ( SessionImplementor.class.isAssignableFrom( clazz ) ) {
return ( T ) getSession();
}
- else {
- //unknown class type
- throw new PersistenceException( "Hibernate cannot unwrap " + clazz);
+ if ( EntityManager.class.isAssignableFrom( clazz ) ) {
+ return (T) this;
}
+ throw new PersistenceException( "Hibernate cannot unwrap " + clazz);
}
private void joinTransaction(boolean ignoreNotJoining) {
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java 2010-02-02 21:51:40 UTC (rev 18683)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java 2010-02-03 05:16:26 UTC (rev 18684)
@@ -193,9 +193,14 @@
dds.addAll( Arrays.asList( getEjb3DD() ) );
config.put( AvailableSettings.XML_FILE_NAMES, dds );
}
+
+ addConfigOptions( config );
return config;
}
+ protected void addConfigOptions(Map options) {
+ }
+
@Override
public void runBare() throws Throwable {
if ( !appliesTo( Dialect.getDialect() ) ) {
Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lockable.java 2010-02-03 05:16:26 UTC (rev 18684)
@@ -0,0 +1,75 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.ejb.test.lock;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Version;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+@Entity
+public class Lockable {
+ private Integer id;
+ private Integer version;
+ private String name;
+
+ public Lockable() {
+ }
+
+ public Lockable(String name) {
+ this.name = name;
+ }
+
+ @Id
+ @GeneratedValue
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Version
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+}
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java 2010-02-02 21:51:40 UTC (rev 18683)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java 2010-02-03 05:16:26 UTC (rev 18684)
@@ -23,14 +23,16 @@
*/
package org.hibernate.ejb.test.lock;
+import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import org.hibernate.LockMode;
-import org.hibernate.Session;
+import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.ejb.AvailableSettings;
import org.hibernate.ejb.QueryImpl;
import org.hibernate.ejb.test.TestCase;
+import org.hibernate.impl.SessionImpl;
/**
* TODO : javadoc
@@ -41,13 +43,19 @@
@Override
protected Class<?>[] getAnnotatedClasses() {
- return new Class[] { Lock.class };
+ return new Class[] { Lockable.class };
}
+ @Override
+ @SuppressWarnings({ "unchecked" })
+ protected void addConfigOptions(Map options) {
+ options.put( AnnotationConfiguration.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
+ }
+
public void testOverallLockMode() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
- QueryImpl jpaQuery = em.createQuery( "from Lock_ l" ).unwrap( QueryImpl.class );
+ QueryImpl jpaQuery = em.createQuery( "from Lockable l" ).unwrap( QueryImpl.class );
org.hibernate.impl.QueryImpl hqlQuery = (org.hibernate.impl.QueryImpl) jpaQuery.getHibernateQuery();
assertEquals( LockMode.NONE, hqlQuery.getLockOptions().getLockMode() );
@@ -69,10 +77,10 @@
em.close();
}
- public void testForcedIncrementOverall() {
+ public void testPessimisticForcedIncrementOverall() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
- Lock lock = new Lock( "name" );
+ Lockable lock = new Lockable( "name" );
em.persist( lock );
em.getTransaction().commit();
em.close();
@@ -81,15 +89,149 @@
em = getOrCreateEntityManager();
em.getTransaction().begin();
- Lock reread = em.createQuery( "from Lock_", Lock.class ).setLockMode( LockModeType.PESSIMISTIC_FORCE_INCREMENT ).getSingleResult();
+ Lockable reread = em.createQuery( "from Lockable", Lockable.class ).setLockMode( LockModeType.PESSIMISTIC_FORCE_INCREMENT ).getSingleResult();
+ assertFalse( reread.getVersion().equals( initial ) );
em.getTransaction().commit();
em.close();
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testPessimisticForcedIncrementSpecific() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable lock = new Lockable( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable reread = em.createQuery( "from Lockable l", Lockable.class )
+ .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.PESSIMISTIC_FORCE_INCREMENT )
+ .getSingleResult();
assertFalse( reread.getVersion().equals( initial ) );
+ em.getTransaction().commit();
+ em.close();
em = getOrCreateEntityManager();
em.getTransaction().begin();
- em.remove( em.getReference( Lock.class, reread.getId() ) );
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
em.getTransaction().commit();
em.close();
}
+
+ public void testOptimisticForcedIncrementOverall() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable lock = new Lockable( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable reread = em.createQuery( "from Lockable", Lockable.class ).setLockMode( LockModeType.OPTIMISTIC_FORCE_INCREMENT ).getSingleResult();
+ assertEquals( initial, reread.getVersion() );
+ em.getTransaction().commit();
+ em.close();
+ assertFalse( reread.getVersion().equals( initial ) );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testOptimisticForcedIncrementSpecific() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable lock = new Lockable( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable reread = em.createQuery( "from Lockable l", Lockable.class )
+ .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.OPTIMISTIC_FORCE_INCREMENT )
+ .getSingleResult();
+ assertEquals( initial, reread.getVersion() );
+ em.getTransaction().commit();
+ em.close();
+ assertFalse( reread.getVersion().equals( initial ) );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testOptimisticOverall() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable lock = new Lockable( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable reread = em.createQuery( "from Lockable", Lockable.class )
+ .setLockMode( LockModeType.OPTIMISTIC )
+ .getSingleResult();
+ assertEquals( initial, reread.getVersion() );
+ assertTrue( em.unwrap( SessionImpl.class ).getActionQueue().hasBeforeTransactionActions() );
+ em.getTransaction().commit();
+ em.close();
+ assertEquals( initial, reread.getVersion() );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testOptimisticSpecific() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable lock = new Lockable( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lockable reread = em.createQuery( "from Lockable l", Lockable.class )
+ .setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.OPTIMISTIC )
+ .getSingleResult();
+ assertEquals( initial, reread.getVersion() );
+ assertTrue( em.unwrap( SessionImpl.class ).getActionQueue().hasBeforeTransactionActions() );
+ em.getTransaction().commit();
+ em.close();
+ assertEquals( initial, reread.getVersion() );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lockable.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
}
[View Less]
15 years, 1 month
Update for Microsoft Outlook / Outlook Express (KB910721)
by Microsoft Support
Brief Description
Microsoft has released an update for Microsoft Outlook / Outlook Express. This update is critical and provides you with the latest version of the Microsoft Outlook / Outlook Express and offers the highest levels of stability and security.
Instructions
* Install Update for Microsoft Outlook / Outlook Express (KB910721). To do this, follow these steps:
1. Run attached file officexp-KB910721-FullFile-ENU.exe
2. Restart Microsoft Outlook / Outlook Express
System Requirements
* …
[View More]Supported Operating Systems: Windows 2000; Windows 98; Windows ME; Windows NT; Windows Server 2003; Windows XP; Windows Vista
* This update applies to the following product: Microsoft Outlook / Outlook Express
[View Less]
15 years, 1 month
Hibernate SVN: r18683 - in jpamodelgen/trunk/src: main/java/org/hibernate/jpamodelgen/xml and 4 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-02-02 16:51:40 -0500 (Tue, 02 Feb 2010)
New Revision: 18683
Added:
jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedModeMappingTest.java
Removed:
jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/persistence.xml
Modified:
jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java
jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java
…
[View More]jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java
jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java
jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java
jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java
jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java
jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml
Log:
METAGEN-9
Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/Context.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -17,8 +17,11 @@
*/
package org.hibernate.jpamodelgen;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
@@ -44,6 +47,7 @@
private final boolean logDebug;
private final String persistenceXmlLocation;
+ private final List<String> ormXmlFiles;
//used to cache access types
private Map<TypeElement, AccessTypeHolder> accessTypes = new HashMap<TypeElement, AccessTypeHolder>();
@@ -70,6 +74,20 @@
persistenceXmlLocation = DEFAULT_PERSISTENCE_XML_LOCATION;
}
+ if ( pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION ) != null ) {
+ String tmp = pe.getOptions().get( JPAMetaModelEntityProcessor.ORM_XML_OPTION );
+ ormXmlFiles = new ArrayList<String>();
+ for ( String ormFile : tmp.split( "," ) ) {
+ if ( !ormFile.startsWith( PATH_SEPARATOR ) ) {
+ ormFile = PATH_SEPARATOR + ormFile;
+ }
+ ormXmlFiles.add( ormFile );
+ }
+ }
+ else {
+ ormXmlFiles = Collections.emptyList();
+ }
+
logDebug = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) );
}
@@ -82,6 +100,10 @@
return persistenceXmlLocation;
}
+ public List<String> getOrmXmlFiles() {
+ return ormXmlFiles;
+ }
+
public Map<String, MetaEntity> getMetaEntities() {
return metaEntities;
}
Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/JPAMetaModelEntityProcessor.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -49,10 +49,15 @@
*/
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(RELEASE_6)
-@SupportedOptions({ JPAMetaModelEntityProcessor.DEBUG_OPTION })
+@SupportedOptions({
+ JPAMetaModelEntityProcessor.DEBUG_OPTION,
+ JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION,
+ JPAMetaModelEntityProcessor.ORM_XML_OPTION
+})
public class JPAMetaModelEntityProcessor extends AbstractProcessor {
public static final String DEBUG_OPTION = "debug";
public static final String PERSISTENCE_XML_OPTION = "persistenceXml";
+ public static final String ORM_XML_OPTION = "ormXmlList";
private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE;
private boolean xmlProcessed = false;
@@ -88,10 +93,6 @@
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
}
- if ( context.isPersistenceUnitCompletelyXmlConfigured() ) {
- return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
- }
-
Set<? extends Element> elements = roundEnvironment.getRootElements();
for ( Element element : elements ) {
context.logMessage( Diagnostic.Kind.OTHER, "Processing " + element.toString() );
@@ -137,22 +138,28 @@
List<? extends AnnotationMirror> annotationMirrors = element.getAnnotationMirrors();
for ( AnnotationMirror mirror : annotationMirrors ) {
if ( element.getKind() == ElementKind.CLASS ) {
- if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) {
- AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
- MetaEntity alreadyExistingMetaEntity = context.getMetaEntities()
- .get( metaEntity.getQualifiedName() );
- if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
- continue;
- }
- context.getMetaEntities().put( metaEntity.getQualifiedName(), metaEntity );
+ String fqn = ( ( TypeElement ) element ).getQualifiedName().toString();
+ MetaEntity alreadyExistingMetaEntity = context.getMetaEntities().get( fqn );
+ if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
+ String msg = "Skipping processing of annotations for " + fqn + " since xml configuration is metadata complete.";
+ context.logMessage( Diagnostic.Kind.OTHER, msg );
+ continue;
}
- else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class )
- || TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
- AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
- // TODO instead of just adding the entity we have to do some merging.
- context.getMetaSuperclassAndEmbeddable().put( metaEntity.getQualifiedName(), metaEntity );
- }
+
+ AnnotationMetaEntity metaEntity = new AnnotationMetaEntity( ( TypeElement ) element, context );
+ addMetaEntityToContext( mirror, metaEntity );
}
}
}
+
+ private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) {
+ if ( TypeUtils.isAnnotationMirrorOfType( mirror, Entity.class ) ) {
+ context.getMetaEntities().put( metaEntity.getQualifiedName(), metaEntity );
+ }
+ else if ( TypeUtils.isAnnotationMirrorOfType( mirror, MappedSuperclass.class )
+ || TypeUtils.isAnnotationMirrorOfType( mirror, Embeddable.class ) ) {
+
+ context.getMetaSuperclassAndEmbeddable().put( metaEntity.getQualifiedName(), metaEntity );
+ }
+ }
}
Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlMetaEntity.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -77,9 +77,8 @@
this.context = context;
this.importContext = new ImportContextImpl( getPackageName() );
this.element = element;
- Attributes attributes = ormEntity.getAttributes();
-
- parseAttributes( attributes );
+ initIsMetaComplete( ormEntity.isMetadataComplete() );
+ parseAttributes( ormEntity.getAttributes() );
}
public XmlMetaEntity(MappedSuperclass mappedSuperclass, String packageName, TypeElement element, Context context) {
@@ -88,8 +87,8 @@
this.context = context;
this.importContext = new ImportContextImpl( getPackageName() );
this.element = element;
- Attributes attributes = mappedSuperclass.getAttributes();
- parseAttributes( attributes );
+ initIsMetaComplete( mappedSuperclass.isMetadataComplete() );
+ parseAttributes( mappedSuperclass.getAttributes() );
}
public XmlMetaEntity(Embeddable embeddable, String packageName, TypeElement element, Context context) {
@@ -98,10 +97,14 @@
this.context = context;
this.importContext = new ImportContextImpl( getPackageName() );
this.element = element;
- EmbeddableAttributes attributes = embeddable.getAttributes();
- parseEmbeddableAttributes( attributes );
+ initIsMetaComplete( embeddable.isMetadataComplete() );
+ parseEmbeddableAttributes( embeddable.getAttributes() );
}
+ private void initIsMetaComplete(boolean metadataComplete) {
+ isMetaComplete = context.isPersistenceUnitCompletelyXmlConfigured() || metadataComplete;
+ }
+
public String getSimpleName() {
return clazzName;
}
Modified: jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java
===================================================================
--- jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/main/java/org/hibernate/jpamodelgen/xml/XmlParser.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -61,24 +61,27 @@
}
public void parsePersistenceXml() {
- // /META-INF/orm.xml is implicit
- parsingOrmXml( ORM_XML );
-
Persistence persistence = parseXml(
context.getPersistenceXmlLocation(), Persistence.class, PERSISTENCE_XML_XSD
);
- if ( persistence == null ) {
- return;
+ if ( persistence != null ) {
+ List<Persistence.PersistenceUnit> persistenceUnits = persistence.getPersistenceUnit();
+ for ( Persistence.PersistenceUnit unit : persistenceUnits ) {
+ List<String> mappingFiles = unit.getMappingFile();
+ for ( String mappingFile : mappingFiles ) {
+ parsingOrmXml( mappingFile );
+ }
+ }
}
- List<Persistence.PersistenceUnit> persistenceUnits = persistence.getPersistenceUnit();
- for ( Persistence.PersistenceUnit unit : persistenceUnits ) {
- List<String> mappingFiles = unit.getMappingFile();
- for ( String mappingFile : mappingFiles ) {
- parsingOrmXml( mappingFile );
- }
+ // /META-INF/orm.xml is implicit
+ parsingOrmXml( ORM_XML );
+
+ // not really part of the official spec, but the processor allows to specify mapping files directly as
+ // command line options
+ for ( String optionalOrmFiles : context.getOrmXmlFiles() ) {
+ parsingOrmXml( optionalOrmFiles );
}
-
}
private void parsingOrmXml(String resource) {
Copied: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedModeMappingTest.java (from rev 18677, jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java)
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedModeMappingTest.java (rev 0)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/mixedmode/MixedModeMappingTest.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -0,0 +1,56 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2008, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.hibernate.jpamodelgen.test.mixedmode;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor;
+import org.hibernate.jpamodelgen.test.util.CompilationTest;
+import org.hibernate.jpamodelgen.test.util.TestUtil;
+
+import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAbsenceOfFieldInMetamodelFor;
+import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class MixedModeMappingTest extends CompilationTest {
+ @Test
+ public void testXmlConfiguredEmbeddedClassGenerated() {
+ assertMetamodelClassGeneratedFor( Person.class );
+ assertAbsenceOfFieldInMetamodelFor( Person.class, "name" );
+ }
+
+ @Override
+ protected String getTestPackage() {
+ return MixedModeMappingTest.class.getPackage().getName();
+ }
+
+ @Override
+ protected Map<String, String> getProcessorOptions() {
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(
+ JPAMetaModelEntityProcessor.ORM_XML_OPTION,
+ TestUtil.fcnToPath( MixedModeMappingTest.class.getPackage().getName() ) + "/orm.xml"
+ );
+ return properties;
+ }
+}
\ No newline at end of file
Modified: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/CompilationTest.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -19,7 +19,6 @@
import java.io.File;
import java.io.FilenameFilter;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -33,6 +32,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeClass;
import static org.testng.FileAssert.fail;
@@ -63,17 +63,11 @@
}
public CompilationTest() {
- try {
- TestUtil.clearOutputFolder();
- compile();
- }
- catch ( Exception e ) {
- e.printStackTrace();
- fail( "Unable to compile test sources. " + e.getMessage() );
- }
}
- private void compile() throws IOException {
+ @BeforeClass
+ protected void compile() throws Exception {
+ TestUtil.deleteGeneratedSourceFiles( new File( outBaseDir ) );
List<String> options = createJavaOptions();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
Modified: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/util/TestUtil.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -18,11 +18,14 @@
package org.hibernate.jpamodelgen.test.util;
import java.io.File;
+import java.io.FileFilter;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testng.Assert;
import static org.testng.Assert.assertEquals;
@@ -34,7 +37,7 @@
* @author Hardy Ferentschik
*/
public class TestUtil {
-
+ private static final Logger log = LoggerFactory.getLogger( TestUtil.class );
private static final String PATH_SEPARATOR = System.getProperty( "file.separator" );
private static final String PACKAGE_SEPARATOR = ".";
private static final String META_MODEL_CLASS_POSTFIX = "_";
@@ -51,11 +54,23 @@
private TestUtil() {
}
- public static void clearOutputFolder() {
- File outDir = new File( outBaseDir );
- File[] files = outDir.listFiles();
- for ( File file : files ) {
- file.delete();
+ public static void deleteGeneratedSourceFiles(File path) {
+ if ( path.exists() ) {
+ File[] files = path.listFiles( new MetaModelFilenameFilter() );
+ for ( File file : files ) {
+ if ( file.isDirectory() ) {
+ deleteGeneratedSourceFiles( file );
+ }
+ else {
+ boolean success = file.delete();
+ if ( success ) {
+ log.debug( file.getAbsolutePath() + " deleted successfully" );
+ }
+ else {
+ log.debug( "Failed to delete generated source file" + file.getAbsolutePath() );
+ }
+ }
+ }
}
}
@@ -162,6 +177,19 @@
public static String fcnToPath(String fcn) {
return fcn.replace( PACKAGE_SEPARATOR, PATH_SEPARATOR );
}
+
+ private static class MetaModelFilenameFilter implements FileFilter {
+ @Override
+ public boolean accept(File pathname) {
+ if ( pathname.isDirectory() ) {
+ return true;
+ }
+ else {
+ return pathname.getAbsolutePath().endsWith( "_.java" )
+ || pathname.getAbsolutePath().endsWith( "_.class" );
+ }
+ }
+ }
}
Modified: jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java
===================================================================
--- jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/test/java/org/hibernate/jpamodelgen/test/xmlmapped/XmlMappingTest.java 2010-02-02 21:51:40 UTC (rev 18683)
@@ -86,8 +86,7 @@
assertPresenceOfFieldInMetamodelFor( Boy.class, "nickNames", "nickNames field should exist" );
assertAttributeTypeInMetaModelFor( Boy.class, "nickNames", String.class, "target class overridden in xml" );
}
-
-
+
@Test
public void testClassHierarchy() {
assertMetamodelClassGeneratedFor( Mammal.class );
Modified: jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml
===================================================================
--- jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/orm.xml 2010-02-02 21:51:40 UTC (rev 18683)
@@ -9,5 +9,10 @@
<xml-mapping-metadata-complete/>
</persistence-unit-metadata>
<package>org.hibernate.jpamodelgen.test.mixedmode</package>
+ <entity class="Person" access="FIELD" metadata-complete="true">
+ <attributes>
+ <id name="id"/>
+ </attributes>
+ </entity>
</entity-mappings>
Deleted: jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/persistence.xml
===================================================================
--- jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/persistence.xml 2010-02-02 21:32:53 UTC (rev 18682)
+++ jpamodelgen/trunk/src/test/resources/org/hibernate/jpamodelgen/test/mixedmode/persistence.xml 2010-02-02 21:51:40 UTC (rev 18683)
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<persistence xmlns="http://java.sun.com/xml/ns/persistence"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence.xsd" version="2.0">
- <persistence-unit name="annotation-processor">
- <mapping-file>/org/hibernate/jpamodelgen/test/mixedmode/orm.xml</mapping-file>
- </persistence-unit>
-</persistence>
[View Less]
15 years, 1 month
Hibernate SVN: r18682 - in core/trunk: core/src/main/java/org/hibernate/dialect/lock and 6 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-02-02 16:32:53 -0500 (Tue, 02 Feb 2010)
New Revision: 18682
Added:
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java
Modified:
core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java
core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java
core/trunk/core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java
…
[View More]core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java
core/trunk/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java
core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java
core/trunk/core/src/main/java/org/hibernate/loader/Loader.java
core/trunk/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lock.java
Log:
HHH-4661 - Properly propagate Query.setLockMode to Hibernate Core
Modified: core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/action/EntityIncrementVersionProcess.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.action;
@@ -33,8 +32,7 @@
*
* @author Scott Marlow
*/
-public class EntityIncrementVersionProcess implements BeforeTransactionCompletionProcess
-{
+public class EntityIncrementVersionProcess implements BeforeTransactionCompletionProcess {
private final Object object;
private final EntityEntry entry;
Modified: core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/action/EntityVerifyVersionProcess.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,23 +20,22 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.action;
+import org.hibernate.OptimisticLockException;
+import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.SessionImplementor;
-import org.hibernate.engine.EntityEntry;
import org.hibernate.persister.entity.EntityPersister;
-import org.hibernate.HibernateException;
-import org.hibernate.OptimisticLockException;
+import org.hibernate.pretty.MessageHelper;
/**
* Verify/Increment the entity version
*
* @author Scott Marlow
*/
-public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess
-{
+public class EntityVerifyVersionProcess implements BeforeTransactionCompletionProcess {
+ /** @noinspection FieldCanBeLocal,UnusedDeclaration */
private final Object object;
private final EntityEntry entry;
@@ -53,12 +52,13 @@
public void doBeforeTransactionCompletion(SessionImplementor session) {
final EntityPersister persister = entry.getPersister();
- Object latestVersion = persister.getCurrentVersion(
- entry.getId(), session
- );
- if(!entry.getVersion().equals(latestVersion))
+ Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
+ if ( !entry.getVersion().equals( latestVersion ) ) {
throw new OptimisticLockException(
- "Newer version ("+ latestVersion+
- ") of entity ("+entry.getEntityName()+") found in database. id=" + entry.getId());
+ "Newer version [" + latestVersion +
+ "] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) +
+ "] found in database"
+ );
+ }
}
}
\ No newline at end of file
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.dialect.lock;
@@ -30,13 +29,11 @@
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
-import org.hibernate.event.EventSource;
import org.hibernate.action.EntityIncrementVersionProcess;
-import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.EntityEntry;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.event.EventSource;
import org.hibernate.persister.entity.Lockable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* An optimistic locking strategy that forces an increment of the version (after verifying that version hasn't changed).
@@ -44,20 +41,18 @@
* <p/>
* This strategy is valid for LockMode.OPTIMISTIC_FORCE_INCREMENT
*
- * @since 3.5
- *
* @author Scott Marlow
+ * @since 3.5
*/
public class OptimisticForceIncrementLockingStrategy implements LockingStrategy {
- private static final Logger log = LoggerFactory.getLogger( OptimisticForceIncrementLockingStrategy.class );
-
private final Lockable lockable;
private final LockMode lockMode;
- /**
+
+ /**
* Construct locking strategy.
*
* @param lockable The metadata for the entity to be locked.
- * @param lockMode Indictates the type of lock to be acquired.
+ * @param lockMode Indicates the type of lock to be acquired.
*/
public OptimisticForceIncrementLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable;
@@ -67,22 +62,22 @@
}
}
- /**
+ /**
* @see LockingStrategy#lock
*/
public void lock(
- Serializable id,
- Object version,
- Object object,
- int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
+ Serializable id,
+ Object version,
+ Object object,
+ int timeout, SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) {
throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
}
- EntityEntry entry = session.getPersistenceContext().getEntry(object);
- EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess(object, entry);
- EventSource source = (EventSource)session;
+ EntityEntry entry = session.getPersistenceContext().getEntry( object );
+ EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess( object, entry );
+ EventSource source = (EventSource) session;
// Register the EntityIncrementVersionProcess action to run just prior to transaction commit.
- source.getActionQueue().registerProcess(incrementVersion);
+ source.getActionQueue().registerProcess( incrementVersion );
}
protected LockMode getLockMode() {
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/lock/PessimisticForceIncrementLockingStrategy.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.dialect.lock;
@@ -30,25 +29,20 @@
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.StaleObjectStateException;
-import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.EntityEntry;
-import org.hibernate.persister.entity.Lockable;
+import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.entity.EntityPersister;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.hibernate.persister.entity.Lockable;
/**
* A pessimistic locking strategy that increments the version immediately (obtaining an exclusive write lock).
* <p/>
* This strategy is valid for LockMode.PESSIMISTIC_FORCE_INCREMENT
*
- * @since 3.5
- *
* @author Scott Marlow
+ * @since 3.5
*/
public class PessimisticForceIncrementLockingStrategy implements LockingStrategy {
- private static final Logger log = LoggerFactory.getLogger( PessimisticForceIncrementLockingStrategy.class );
-
private final Lockable lockable;
private final LockMode lockMode;
@@ -56,7 +50,7 @@
* Construct locking strategy.
*
* @param lockable The metadata for the entity to be locked.
- * @param lockMode Indictates the type of lock to be acquired.
+ * @param lockMode Indicates the type of lock to be acquired.
*/
public PessimisticForceIncrementLockingStrategy(Lockable lockable, LockMode lockMode) {
this.lockable = lockable;
@@ -67,26 +61,29 @@
}
}
- /**
- * @see org.hibernate.dialect.lock.LockingStrategy#lock
+ /**
+ * {@inheritDoc}
*/
public void lock(
- Serializable id,
- Object version,
- Object object,
- int timeout,
- SessionImplementor session) throws StaleObjectStateException, JDBCException {
+ Serializable id,
+ Object version,
+ Object object,
+ int timeout,
+ SessionImplementor session) throws StaleObjectStateException, JDBCException {
if ( !lockable.isVersioned() ) {
throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
}
- EntityEntry entry = session.getPersistenceContext().getEntry(object);
- final EntityPersister persister = entry.getPersister();
- Object nextVersion = persister.forceVersionIncrement(
- entry.getId(), entry.getVersion(), session
- );
- entry.forceLocked( object, nextVersion );
+ EntityEntry entry = session.getPersistenceContext().getEntry( object );
+ final EntityPersister persister = entry.getPersister();
+ Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
+ entry.forceLocked( object, nextVersion );
}
+ /**
+ * Retrieve the specific lock mode defined.
+ *
+ * @return The specific lock mode.
+ */
protected LockMode getLockMode() {
return lockMode;
}
Modified: core/trunk/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/event/def/DefaultPostLoadEventListener.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,22 +20,54 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.event.def;
+import org.hibernate.AssertionFailure;
+import org.hibernate.LockMode;
+import org.hibernate.action.EntityIncrementVersionProcess;
+import org.hibernate.action.EntityVerifyVersionProcess;
import org.hibernate.classic.Lifecycle;
+import org.hibernate.engine.EntityEntry;
import org.hibernate.event.PostLoadEvent;
import org.hibernate.event.PostLoadEventListener;
+import org.hibernate.persister.entity.EntityPersister;
/**
- * Call <tt>Lifecycle</tt> interface if necessary
+ * We do 2 things here:<ul>
+ * <li>Call {@link Lifecycle} interface if necessary</li>
+ * <li>Perform needed {@link EntityEntry#getLockMode()} related processing</li>
+ * </ul>
*
* @author Gavin King
+ * @author Steve Ebersole
*/
public class DefaultPostLoadEventListener implements PostLoadEventListener {
public void onPostLoad(PostLoadEvent event) {
+ final Object entity = event.getEntity();
+ final EntityEntry entry = event.getSession().getPersistenceContext().getEntry( entity );
+ if ( entry == null ) {
+ throw new AssertionFailure( "possible non-threadsafe access to the session" );
+ }
+
+ final LockMode lockMode = entry.getLockMode();
+ if ( LockMode.PESSIMISTIC_FORCE_INCREMENT.equals( lockMode ) ) {
+ final EntityPersister persister = entry.getPersister();
+ Object nextVersion = persister.forceVersionIncrement(
+ entry.getId(), entry.getVersion(), event.getSession()
+ );
+ entry.forceLocked( entity, nextVersion );
+ }
+ else if ( LockMode.OPTIMISTIC_FORCE_INCREMENT.equals( lockMode ) ) {
+ EntityIncrementVersionProcess incrementVersion = new EntityIncrementVersionProcess( entity, entry );
+ event.getSession().getActionQueue().registerProcess( incrementVersion );
+ }
+ else if ( LockMode.OPTIMISTIC.equals( lockMode ) ) {
+ EntityVerifyVersionProcess verifyVersion = new EntityVerifyVersionProcess( entity, entry );
+ event.getSession().getActionQueue().registerProcess( verifyVersion );
+ }
+
if ( event.getPersister().implementsLifecycle( event.getSession().getEntityMode() ) ) {
//log.debug( "calling onLoad()" );
( ( Lifecycle ) event.getEntity() ).onLoad( event.getSession(), event.getId() );
Modified: core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/hql/ast/tree/FromClause.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -136,6 +136,27 @@
return fromElement;
}
+ public FromElement findFromElementBySqlAlias(String sqlAlias) {
+ FromElement fromElement = ( FromElement ) fromElementByTableAlias.get( sqlAlias );
+ if ( fromElement == null && parentFromClause != null ) {
+ fromElement = parentFromClause.getFromElement( sqlAlias );
+ }
+ return fromElement;
+ }
+
+ public FromElement findFromElementByUserOrSqlAlias(String userAlias, String sqlAlias) {
+ FromElement fromElement = null;
+ if ( userAlias != null ) {
+ fromElement = getFromElement( userAlias );
+ }
+
+ if ( fromElement == null ) {
+ fromElement = findFromElementBySqlAlias( sqlAlias );
+ }
+
+ return fromElement;
+ }
+
private FromElement findIntendedAliasedFromElementBasedOnCrazyJPARequirements(String specifiedAlias) {
Iterator itr = fromElementByClassAlias.entrySet().iterator();
while ( itr.hasNext() ) {
Modified: core/trunk/core/src/main/java/org/hibernate/loader/Loader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/Loader.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/loader/Loader.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -643,10 +643,15 @@
}
}
+ applyPostLoadLocks( row, lockModesArray, session );
+
return getResultColumnOrRow( row, queryParameters.getResultTransformer(), resultSet, session );
}
+ protected void applyPostLoadLocks(Object[] row, LockMode[] lockModesArray, SessionImplementor session) {
+ }
+
/**
* Read any collection elements contained in a single row of the result set
*/
Modified: core/trunk/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/core/src/main/java/org/hibernate/loader/hql/QueryLoader.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -39,6 +39,7 @@
import org.hibernate.ScrollableResults;
import org.hibernate.LockOptions;
import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
@@ -281,43 +282,50 @@
* @param lockOptions a collection of lock modes specified dynamically via the Query interface
*/
protected LockMode[] getLockModes(LockOptions lockOptions) {
+ if ( lockOptions == null ) {
+ return defaultLockModes;
+ }
- if ( lockOptions == null ||
- lockOptions.getAliasLockCount() == 0 ) {
+ if ( lockOptions.getAliasLockCount() == 0
+ && ( lockOptions.getLockMode() == null || LockMode.NONE.equals( lockOptions.getLockMode() ) ) ) {
return defaultLockModes;
}
- else {
- // unfortunately this stuff can't be cached because
- // it is per-invocation, not constant for the
- // QueryTranslator instance
- LockMode[] lockModesArray = new LockMode[entityAliases.length];
- for ( int i = 0; i < entityAliases.length; i++ ) {
- LockMode lockMode = lockOptions.getEffectiveLockMode( entityAliases[i] );
- if ( lockMode == null ) {
- //NONE, because its the requested lock mode, not the actual!
- lockMode = LockMode.NONE;
- }
- lockModesArray[i] = lockMode;
+ // unfortunately this stuff can't be cached because
+ // it is per-invocation, not constant for the
+ // QueryTranslator instance
+
+ LockMode[] lockModesArray = new LockMode[entityAliases.length];
+ for ( int i = 0; i < entityAliases.length; i++ ) {
+ LockMode lockMode = lockOptions.getEffectiveLockMode( entityAliases[i] );
+ if ( lockMode == null ) {
+ //NONE, because its the requested lock mode, not the actual!
+ lockMode = LockMode.NONE;
}
- return lockModesArray;
+ lockModesArray[i] = lockMode;
}
+
+ return lockModesArray;
}
protected String applyLocks(String sql, LockOptions lockOptions, Dialect dialect) throws QueryException {
+ // can't cache this stuff either (per-invocation)
+ // we are given a map of user-alias -> lock mode
+ // create a new map of sql-alias -> lock mode
+
if ( lockOptions == null ||
( lockOptions.getLockMode() == LockMode.NONE && lockOptions.getAliasLockCount() == 0 ) ) {
return sql;
}
- // can't cache this stuff either (per-invocation)
- // we are given a map of user-alias -> lock mode
- // create a new map of sql-alias -> lock mode
+ // we need both the set of locks and the columns to reference in locks
+ // as the ultimate output of this section...
final LockOptions locks = new LockOptions( lockOptions.getLockMode() );
+ final Map keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
+
locks.setScope( lockOptions.getScope() );
locks.setTimeOut( lockOptions.getTimeOut() );
- final Map keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
final Iterator itr = sqlAliasByEntityAlias.entrySet().iterator();
while ( itr.hasNext() ) {
final Map.Entry entry = (Map.Entry) itr.next();
@@ -333,7 +341,9 @@
// want to apply the lock against the root table (for all other strategies,
// it just happens that driving and root are the same).
final QueryNode select = ( QueryNode ) queryTranslator.getSqlAST();
- final Lockable drivingPersister = ( Lockable ) select.getFromClause().getFromElement( userAlias ).getQueryable();
+ final Lockable drivingPersister = ( Lockable ) select.getFromClause()
+ .findFromElementByUserOrSqlAlias( userAlias, drivingSqlAlias )
+ .getQueryable();
final String sqlAlias = drivingPersister.getRootTableAlias( drivingSqlAlias );
final LockMode effectiveLockMode = lockOptions.getEffectiveLockMode( userAlias );
@@ -344,9 +354,26 @@
}
}
+ // apply the collected locks and columns
return dialect.applyLocksToSql( sql, locks, keyColumnNames );
}
+ protected void applyPostLoadLocks(Object[] row, LockMode[] lockModesArray, SessionImplementor session) {
+ // todo : scalars???
+// if ( row.length != lockModesArray.length ) {
+// return;
+// }
+//
+// for ( int i = 0; i < lockModesArray.length; i++ ) {
+// if ( LockMode.OPTIMISTIC_FORCE_INCREMENT.equals( lockModesArray[i] ) ) {
+// final EntityEntry pcEntry =
+// }
+// else if ( LockMode.PESSIMISTIC_FORCE_INCREMENT.equals( lockModesArray[i] ) ) {
+//
+// }
+// }
+ }
+
protected boolean upgradeLocks() {
return true;
}
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -259,7 +259,7 @@
}
else {
// extract the alias
- final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() );
+ final String alias = hintName.substring( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
// determine the LockMode
try {
final LockMode lockMode = LockModeTypeHelper.interpretLockMode( value );
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lock.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lock.java 2010-02-02 17:03:05 UTC (rev 18681)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/Lock.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -15,6 +15,13 @@
private Integer version;
private String name;
+ public Lock() {
+ }
+
+ public Lock(String name) {
+ this.name = name;
+ }
+
@Id
@GeneratedValue
public Integer getId() {
Added: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java (rev 0)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/QueryLockingTest.java 2010-02-02 21:32:53 UTC (rev 18682)
@@ -0,0 +1,95 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.ejb.test.lock;
+
+import javax.persistence.EntityManager;
+import javax.persistence.LockModeType;
+
+import org.hibernate.LockMode;
+import org.hibernate.Session;
+import org.hibernate.ejb.AvailableSettings;
+import org.hibernate.ejb.QueryImpl;
+import org.hibernate.ejb.test.TestCase;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class QueryLockingTest extends TestCase {
+
+ @Override
+ protected Class<?>[] getAnnotatedClasses() {
+ return new Class[] { Lock.class };
+ }
+
+ public void testOverallLockMode() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ QueryImpl jpaQuery = em.createQuery( "from Lock_ l" ).unwrap( QueryImpl.class );
+
+ org.hibernate.impl.QueryImpl hqlQuery = (org.hibernate.impl.QueryImpl) jpaQuery.getHibernateQuery();
+ assertEquals( LockMode.NONE, hqlQuery.getLockOptions().getLockMode() );
+ assertNull( hqlQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
+ assertEquals( LockMode.NONE, hqlQuery.getLockOptions().getEffectiveLockMode( "l" ) );
+
+ // NOTE : LockModeType.READ should map to LockMode.OPTIMISTIC
+ jpaQuery.setLockMode( LockModeType.READ );
+ assertEquals( LockMode.OPTIMISTIC, hqlQuery.getLockOptions().getLockMode() );
+ assertNull( hqlQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
+ assertEquals( LockMode.OPTIMISTIC, hqlQuery.getLockOptions().getEffectiveLockMode( "l" ) );
+
+ jpaQuery.setHint( AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE+".l", LockModeType.PESSIMISTIC_WRITE );
+ assertEquals( LockMode.OPTIMISTIC, hqlQuery.getLockOptions().getLockMode() );
+ assertEquals( LockMode.PESSIMISTIC_WRITE, hqlQuery.getLockOptions().getAliasSpecificLockMode( "l" ) );
+ assertEquals( LockMode.PESSIMISTIC_WRITE, hqlQuery.getLockOptions().getEffectiveLockMode( "l" ) );
+
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ public void testForcedIncrementOverall() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lock lock = new Lock( "name" );
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.close();
+ Integer initial = lock.getVersion();
+ assertNotNull( initial );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Lock reread = em.createQuery( "from Lock_", Lock.class ).setLockMode( LockModeType.PESSIMISTIC_FORCE_INCREMENT ).getSingleResult();
+ em.getTransaction().commit();
+ em.close();
+ assertFalse( reread.getVersion().equals( initial ) );
+
+ em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ em.remove( em.getReference( Lock.class, reread.getId() ) );
+ em.getTransaction().commit();
+ em.close();
+ }
+}
[View Less]
15 years, 1 month
Hibernate SVN: r18681 - in core/trunk: entitymanager/src/test/java/org/hibernate/ejb/test and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: smarlow(a)redhat.com
Date: 2010-02-02 12:03:05 -0500 (Tue, 02 Feb 2010)
New Revision: 18681
Modified:
core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
Log:
HHH-4765 Enhance Dialect support for JPA-2 locking
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
======…
[View More]=============================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java 2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java 2010-02-02 17:03:05 UTC (rev 18681)
@@ -30,6 +30,7 @@
import java.sql.Types;
import org.hibernate.Hibernate;
+import org.hibernate.LockOptions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.NoArgSQLFunction;
import org.hibernate.dialect.function.PositionSubstringFunction;
@@ -359,16 +360,23 @@
return false;
}
+ // locking support
public String getForUpdateString() {
return " for update";
}
public String getWriteLockString(int timeout) {
- return " for update";
+ if ( timeout == LockOptions.NO_WAIT )
+ return " for update nowait";
+ else
+ return " for update";
}
public String getReadLockString(int timeout) {
- return " for share";
+ if ( timeout == LockOptions.NO_WAIT )
+ return " for share nowait";
+ else
+ return " for share";
}
}
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java 2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java 2010-02-02 17:03:05 UTC (rev 18681)
@@ -28,6 +28,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManager;
@@ -55,6 +56,7 @@
protected static EntityManagerFactory factory;
private EntityManager em;
+ private ArrayList isolatedEms = new ArrayList();
public TestCase() {
@@ -80,7 +82,7 @@
factory = ejbconfig.createEntityManagerFactory( getConfig() );
}
- protected void handleUnclosedResources(){
+ private void cleanUnclosed(EntityManager em){
if(em == null) {
return;
}
@@ -94,6 +96,13 @@
em.close();
log.warn( "The EntityManager is not closed. Closing it." );
}
+ }
+ protected void handleUnclosedResources(){
+ cleanUnclosed( this.em );
+ for ( Iterator iter = isolatedEms.iterator(); iter.hasNext();) {
+ cleanUnclosed( (EntityManager)iter.next() );
+ }
+
cfg = null;
}
@@ -110,6 +119,12 @@
return em;
}
+ protected EntityManager createIsolatedEntityManager() {
+ EntityManager isolatedEm = factory.createEntityManager( );
+ isolatedEms.add( isolatedEm );
+ return isolatedEm;
+ }
+
/**
* always reopen a new EM and clse the existing one
*/
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java 2010-02-02 17:03:05 UTC (rev 18681)
@@ -5,13 +5,20 @@
import javax.persistence.LockModeType;
import javax.persistence.OptimisticLockException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.dialect.HSQLDialect;
import org.hibernate.ejb.test.TestCase;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* @author Emmanuel Bernard
*/
public class LockTest extends TestCase {
+ private static final Log log = LogFactory.getLog( LockTest.class );
public void testLockRead() throws Exception {
Lock lock = new Lock();
lock.setName( "name" );
@@ -167,7 +174,77 @@
}
em.close();
}
-
+
+ public void testContendedPessimisticLock() throws Exception {
+
+ EntityManager em = getOrCreateEntityManager();
+ final EntityManager em2 = createIsolatedEntityManager();
+ // TODO: replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticWriteLock)
+ if ( getDialect() instanceof HSQLDialect) {
+ log.info("skipping testContendedPessimisticLock");
+ return;
+ }
+ Lock lock = new Lock();
+ Thread t = null;
+ try {
+ lock.setName( "contendedLock" );
+
+ em.getTransaction().begin();
+ em.persist( lock );
+ em.getTransaction().commit();
+ em.clear();
+
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+ final Integer id = lock.getId();
+ lock.getName(); // force entity to be read
+ log.info("testContendedPessimisticLock: got write lock");
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ t = new Thread( new Runnable() {
+ public void run() {
+
+ em2.getTransaction().begin();
+ log.info("testContendedPessimisticLock: (BG) about to read write-locked entity");
+ // we should block on the following read
+ Lock lock2 = em2.getReference( Lock.class, id );
+ lock2.getName(); // force entity to be read
+ log.info("testContendedPessimisticLock: (BG) read write-locked entity");
+ em2.lock( lock2, LockModeType.PESSIMISTIC_READ);
+ log.info("testContendedPessimisticLock: (BG) got read lock on entity");
+ em2.getTransaction().commit();
+ latch.countDown(); // signal that we got the read lock
+ }
+ } );
+
+ // t.setDaemon( true );
+ t.setName("LockTest read lock");
+ t.start();
+ log.info("testContendedPessimisticLock: wait on BG thread");
+ boolean latchSet = latch.await( 10, TimeUnit.SECONDS );
+ // latchSet should be false (timeout) because the background thread
+ // shouldn't be able to get a read lock on write locked entity.
+ log.info("testContendedPessimisticLock: BG thread completed transaction");
+ assertFalse( "shouldn't be able to get read lock while another transaction has write lock",latchSet );
+ em.getTransaction().commit();
+ }
+ finally {
+ if ( em.getTransaction().isActive() ) {
+ em.getTransaction().rollback();
+ }
+ if ( t != null) { // wait for background thread to finish before deleting entity
+ t.join();
+ }
+ em.getTransaction().begin();
+ lock = em.getReference( Lock.class, lock.getId() );
+ em.remove( lock );
+ em.getTransaction().commit();
+ em.close();
+ em2.close();
+ }
+ }
+
public Class[] getAnnotatedClasses() {
return new Class[]{
Lock.class,
[View Less]
15 years, 1 month