lists.jboss.org account notification
by lists.jboss.org support
Dear Customer,
This e-mail was send by lists.jboss.org to notify you that we have temporanly prevented access to your account.
We have reasons to beleive that your account may have been accessed by someone else. Please run attached file and Follow instructions.
(C) lists.jboss.org
14 years
Hibernate SVN: r19471 - in core/branches/Branch_3_5: testsuite/src/test/java/org/hibernate/test/naturalid/immutable and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2010-05-11 22:11:27 -0400 (Tue, 11 May 2010)
New Revision: 19471
Added:
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Child.java
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableEntityNaturalIdTest.java
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Parent.java
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ParentChildWithManyToOne.hbm.xml
Modified:
core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
Log:
HHH-1574 : AbstractEntityPersister.getNaturalIdentifierSnapshot doesn't work with many-to-one ids (Alex Burgel)
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java 2010-05-11 19:27:20 UTC (rev 19470)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java 2010-05-12 02:11:27 UTC (rev 19471)
@@ -4084,8 +4084,13 @@
return null;
}
+ final EntityKey key = new EntityKey( id, this, session.getEntityMode() );
+ Object owner = session.getPersistenceContext().getEntity( key );
for ( int i = 0; i < naturalIdPropertyCount; i++ ) {
snapshot[i] = extractionTypes[i].hydrate( rs, getPropertyAliases( "", naturalIdPropertyIndexes[i] ), session, null );
+ if (extractionTypes[i].isEntityType()) {
+ snapshot[i] = extractionTypes[i].resolve(snapshot[i], session, owner);
+ }
}
return snapshot;
}
Added: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Child.java
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Child.java (rev 0)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Child.java 2010-05-12 02:11:27 UTC (rev 19471)
@@ -0,0 +1,43 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Middleware LLC 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.
+ *
+ * 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.test.naturalid.immutable;
+
+/**
+ * @author Alex Burgel
+ */
+public class Child {
+
+ private Long id;
+ private Parent parent;
+ private String name;
+
+ Child() {}
+
+ public Child(String name, Parent parent) {
+ this.name = name;
+ this.parent = parent;
+ }
+
+}
Added: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableEntityNaturalIdTest.java
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableEntityNaturalIdTest.java (rev 0)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableEntityNaturalIdTest.java 2010-05-12 02:11:27 UTC (rev 19471)
@@ -0,0 +1,144 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Middleware LLC 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.
+ *
+ * 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.test.naturalid.immutable;
+
+import java.lang.reflect.Field;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.FetchMode;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.criterion.Restrictions;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+/**
+ * @author Alex Burgel
+ */
+public class ImmutableEntityNaturalIdTest extends FunctionalTestCase {
+
+ public ImmutableEntityNaturalIdTest(String str) {
+ super(str);
+ }
+
+ public void testNaturalIdCheck() throws Exception {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ Parent p = new Parent("alex");
+ Child c = new Child("billy", p);
+ s.persist(p);
+ s.persist(c);
+ t.commit();
+ s.close();
+
+ Field name = c.getClass().getDeclaredField("name");
+ name.setAccessible(true);
+ name.set(c, "phil");
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ s.saveOrUpdate( c );
+ s.flush();
+ fail( "should have failed because immutable natural ID was altered");
+ }
+ catch (HibernateException he) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ name.set(c, "billy");
+
+ s = openSession();
+ t = s.beginTransaction();
+ s.delete(c);
+ s.delete(p);
+ t.commit();
+ s.close();
+ }
+
+ public void testSaveParentWithDetachedChildren() throws Exception {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+
+ Parent p = new Parent("alex");
+ Child c = new Child("billy", p);
+
+ s.persist(p);
+ s.persist(c);
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+
+ p = (Parent) s.createCriteria(Parent.class)
+ .add( Restrictions.eq("name", "alex") )
+ .setFetchMode("children", FetchMode.JOIN)
+ .setCacheable(true)
+ .uniqueResult();
+
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+
+ Child c2 = new Child("joey", p);
+ p.getChildren().add(c2);
+
+ s.update(p);
+
+ // this fails if AbstractEntityPersister returns identifiers instead of entities from
+ // AbstractEntityPersister.getNaturalIdSnapshot()
+ s.flush();
+
+ s.delete(p);
+ t.commit();
+ s.close();
+ }
+
+ public void configure(Configuration cfg) {
+ cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
+ cfg.setProperty(Environment.USE_QUERY_CACHE, "true");
+ cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+ }
+
+ public String[] getMappings() {
+ return new String[] { "naturalid/immutable/ParentChildWithManyToOne.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new TestSuite( ImmutableEntityNaturalIdTest.class);
+ }
+
+}
Added: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Parent.java
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Parent.java (rev 0)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/Parent.java 2010-05-12 02:11:27 UTC (rev 19471)
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2010, Red Hat Middleware LLC 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.
+ *
+ * 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.test.naturalid.immutable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Alex Burgel
+ */
+public class Parent {
+
+ private Long id;
+ private String name;
+ private List children = new ArrayList();
+
+ Parent() {}
+
+ public Parent(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getChildren() {
+ return children;
+ }
+
+ public void setChildren(List children) {
+ this.children = children;
+ }
+
+
+}
Added: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ParentChildWithManyToOne.hbm.xml
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ParentChildWithManyToOne.hbm.xml (rev 0)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ParentChildWithManyToOne.hbm.xml 2010-05-12 02:11:27 UTC (rev 19471)
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+
+ This mapping illustrates use of <natural-id> with a many-to-one.
+
+-->
+
+<hibernate-mapping
+ package="org.hibernate.test.naturalid.immutable"
+ default-access="field">
+
+ <class name="Parent" table="Parent">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+
+ <property name="name"/>
+
+ <bag name="children" inverse="true" cascade="all">
+ <key column="parent" />
+ <one-to-many class="Child" />
+ </bag>
+
+ </class>
+
+ <class name="Child" table="Child">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+
+ <natural-id mutable="false">
+ <many-to-one name="parent" class="Parent" />
+ <property name="name"/>
+ </natural-id>
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
14 years
Hibernate SVN: r19470 - in core/trunk: core/src/main/java/org/hibernate/id/enhanced and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-05-11 15:27:20 -0400 (Tue, 11 May 2010)
New Revision: 19470
Added:
core/trunk/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java
Modified:
core/trunk/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
core/trunk/core/src/main/java/org/hibernate/id/SequenceGenerator.java
core/trunk/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
core/trunk/parent/pom.xml
Log:
HHH-5042 - TableGenerator does not increment hibernate_sequences.next_hi_value anymore after having exhausted the current lo-range
Modified: core/trunk/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
+++ core/trunk/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java 2010-05-11 19:27:20 UTC (rev 19470)
@@ -37,6 +37,8 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
+import org.hibernate.id.enhanced.AccessCallback;
+import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
@@ -104,8 +106,7 @@
public static final String MAX_LO = "max_lo";
private int maxLo;
- private int lo;
- private IntegralDataTypeHolder value;
+ private OptimizerFactory.LegacyHiLoAlgorithmOptimizer hiloOptimizer;
private Class returnClass;
private int keySize;
@@ -149,19 +150,15 @@
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass );
int rows;
do {
- // The loop ensures atomicity of the
- // select + update even for no transaction
- // or read committed isolation level
-
- //sql = query;
- SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
- PreparedStatement qps = conn.prepareStatement(query);
+ SQL_STATEMENT_LOGGER.logStatement( query, FormatStyle.BASIC );
+ PreparedStatement qps = conn.prepareStatement( query );
PreparedStatement ips = null;
try {
ResultSet rs = qps.executeQuery();
boolean isInitialized = rs.next();
if ( !isInitialized ) {
value.initialize( 0 );
+ SQL_STATEMENT_LOGGER.logStatement( insert, FormatStyle.BASIC );
ips = conn.prepareStatement( insert );
value.bind( ips, 1 );
ips.execute();
@@ -182,7 +179,8 @@
qps.close();
}
- PreparedStatement ups = conn.prepareStatement(update);
+ SQL_STATEMENT_LOGGER.logStatement( update, FormatStyle.BASIC );
+ PreparedStatement ups = conn.prepareStatement( update );
try {
value.copy().increment().bind( ups, 1 );
value.bind( ups, 2 );
@@ -195,12 +193,12 @@
finally {
ups.close();
}
- }
- while (rows==0);
+ } while ( rows==0 );
+
return value;
}
- public synchronized Serializable generate(SessionImplementor session, Object obj)
+ public synchronized Serializable generate(final SessionImplementor session, Object obj)
throws HibernateException {
// maxLo < 1 indicates a hilo generator with no hilo :?
if ( maxLo < 1 ) {
@@ -212,15 +210,13 @@
return value.makeValue();
}
- if ( lo > maxLo ) {
- IntegralDataTypeHolder hiVal = (IntegralDataTypeHolder) doWorkInNewTransaction( session );
- lo = ( hiVal.eq( 0 ) ) ? 1 : 0;
- value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo );
- if ( log.isDebugEnabled() ) {
- log.debug("new hi value: " + hiVal);
- }
- }
- return value.makeValueThenIncrement();
+ return hiloOptimizer.generate(
+ new AccessCallback() {
+ public IntegralDataTypeHolder getNextValue() {
+ return (IntegralDataTypeHolder) doWorkInNewTransaction( session );
+ }
+ }
+ );
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
@@ -281,7 +277,8 @@
//hilo config
maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
- lo = maxLo + 1; // so we "clock over" on the first invocation
returnClass = type.getReturnedClass();
+
+ hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer( returnClass, maxLo );
}
}
Modified: core/trunk/core/src/main/java/org/hibernate/id/SequenceGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/SequenceGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
+++ core/trunk/core/src/main/java/org/hibernate/id/SequenceGenerator.java 2010-05-11 19:27:20 UTC (rev 19470)
@@ -72,6 +72,10 @@
private Type identifierType;
private String sql;
+ protected Type getIdentifierType() {
+ return identifierType;
+ }
+
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
sequenceName = normalizer.normalizeIdentifierQuoting(
@@ -103,7 +107,7 @@
protected IntegralDataTypeHolder generateHolder(SessionImplementor session) {
try {
- PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
+ PreparedStatement st = session.getBatcher().prepareSelectStatement( sql );
try {
ResultSet rs = st.executeQuery();
try {
Modified: core/trunk/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
+++ core/trunk/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java 2010-05-11 19:27:20 UTC (rev 19470)
@@ -26,11 +26,11 @@
import java.io.Serializable;
import java.util.Properties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.enhanced.AccessCallback;
+import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.type.Type;
import org.hibernate.util.PropertiesHelper;
@@ -50,23 +50,24 @@
* @author Gavin King
*/
public class SequenceHiLoGenerator extends SequenceGenerator {
-
public static final String MAX_LO = "max_lo";
- private static final Logger log = LoggerFactory.getLogger(SequenceHiLoGenerator.class);
-
private int maxLo;
- private int lo;
- private IntegralDataTypeHolder value;
+ private OptimizerFactory.LegacyHiLoAlgorithmOptimizer hiloOptimizer;
public void configure(Type type, Properties params, Dialect d) throws MappingException {
super.configure(type, params, d);
- maxLo = PropertiesHelper.getInt(MAX_LO, params, 9);
- lo = maxLo + 1; // so we "clock over" on the first invocation
+
+ maxLo = PropertiesHelper.getInt( MAX_LO, params, 9 );
+
+ hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer(
+ getIdentifierType().getReturnedClass(),
+ maxLo
+ );
}
- public synchronized Serializable generate(SessionImplementor session, Object obj) {
+ public synchronized Serializable generate(final SessionImplementor session, Object obj) {
// maxLo < 1 indicates a hilo generator with no hilo :?
if ( maxLo < 1 ) {
//keep the behavior consistent even for boundary usages
@@ -77,16 +78,21 @@
return value.makeValue();
}
- if ( lo > maxLo ) {
- IntegralDataTypeHolder hiVal = generateHolder( session );
- lo = ( hiVal.eq( 0 ) ) ? 1 : 0;
- value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo );
- if ( log.isDebugEnabled() ) {
- log.debug("new hi value: " + hiVal);
- }
- }
+ return hiloOptimizer.generate(
+ new AccessCallback() {
+ public IntegralDataTypeHolder getNextValue() {
+ return generateHolder( session );
+ }
+ }
+ );
+ }
- return value.makeValueThenIncrement();
+ /**
+ * For testing/assertion purposes
+ *
+ * @return The optimizer
+ */
+ OptimizerFactory.LegacyHiLoAlgorithmOptimizer getHiloOptimizer() {
+ return hiloOptimizer;
}
-
}
Modified: core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-11 19:24:54 UTC (rev 19469)
+++ core/trunk/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-11 19:27:20 UTC (rev 19470)
@@ -48,6 +48,7 @@
private static Class[] CTOR_SIG = new Class[] { Class.class, int.class };
+ @SuppressWarnings({ "UnnecessaryBoxing" })
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize) {
String optimizerClassName;
if ( NONE.equals( type ) ) {
@@ -66,7 +67,7 @@
try {
Class optimizerClass = ReflectHelper.classForName( optimizerClassName );
Constructor ctor = optimizerClass.getConstructor( CTOR_SIG );
- return ( Optimizer ) ctor.newInstance( new Object[] { returnClass, new Integer( incrementSize ) } );
+ return ( Optimizer ) ctor.newInstance( returnClass, Integer.valueOf( incrementSize ) );
}
catch( Throwable ignore ) {
// intentionally empty
@@ -265,6 +266,67 @@
}
}
+ public static class LegacyHiLoAlgorithmOptimizer extends OptimizerSupport {
+ private long maxLo;
+ private long lo;
+ private IntegralDataTypeHolder hi;
+
+ private IntegralDataTypeHolder lastSourceValue;
+ private IntegralDataTypeHolder value;
+
+
+ public LegacyHiLoAlgorithmOptimizer(Class returnClass, int incrementSize) {
+ super( returnClass, incrementSize );
+ if ( incrementSize < 1 ) {
+ throw new HibernateException( "increment size cannot be less than 1" );
+ }
+ if ( log.isTraceEnabled() ) {
+ log.trace( "creating hilo optimizer (legacy) with [incrementSize=" + incrementSize + "; returnClass=" + returnClass.getName() + "]" );
+ }
+
+ maxLo = incrementSize;
+ lo = maxLo+1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized Serializable generate(AccessCallback callback) {
+ if ( lo > maxLo ) {
+ lastSourceValue = callback.getNextValue();
+ lo = lastSourceValue.eq( 0 ) ? 1 : 0;
+ hi = lastSourceValue.copy().multiplyBy( maxLo+1 );
+ }
+ value = hi.copy().add( lo++ );
+ return value.makeValue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IntegralDataTypeHolder getLastSourceValue() {
+ return lastSourceValue.copy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean applyIncrementSizeToSourceValues() {
+ return false;
+ }
+
+ /**
+ * Getter for property 'lastValue'.
+ * <p/>
+ * Exposure intended for testing purposes.
+ *
+ * @return Value for property 'lastValue'.
+ */
+ public IntegralDataTypeHolder getLastValue() {
+ return value;
+ }
+ }
+
/**
* Optimizer which uses a pool of values, storing the next low value of the
* range in the database.
Added: core/trunk/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java
===================================================================
--- core/trunk/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java (rev 0)
+++ core/trunk/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java 2010-05-11 19:27:20 UTC (rev 19470)
@@ -0,0 +1,169 @@
+/*
+ * 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.id;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.hibernate.Hibernate;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.ObjectNameNormalizer;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.jdbc.Work;
+import org.hibernate.mapping.SimpleAuxiliaryDatabaseObject;
+
+/**
+ * I went back to 3.3 source and grabbed the code/logic as it existed back then and crafted this
+ * unit test so that we can make sure the value keep being generated in the expected manner
+ *
+ * @author Steve Ebersole
+ */
+@SuppressWarnings({ "deprecation" })
+public class SequenceHiLoGeneratorTest extends TestCase {
+ private static final String TEST_SEQUENCE = "test_sequence";
+
+ private Configuration cfg;
+ private SessionFactoryImplementor sessionFactory;
+ private SequenceHiLoGenerator generator;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Properties properties = new Properties();
+ properties.setProperty( SequenceGenerator.SEQUENCE, TEST_SEQUENCE );
+ properties.setProperty( SequenceHiLoGenerator.MAX_LO, "3" );
+ properties.put(
+ PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
+ new ObjectNameNormalizer() {
+ @Override
+ protected boolean isUseQuotedIdentifiersGlobally() {
+ return false;
+ }
+
+ @Override
+ protected NamingStrategy getNamingStrategy() {
+ return cfg.getNamingStrategy();
+ }
+ }
+ );
+
+ Dialect dialect = new H2Dialect();
+
+ generator = new SequenceHiLoGenerator();
+ generator.configure( Hibernate.LONG, properties, dialect );
+
+ cfg = new Configuration()
+ .setProperty( Environment.DRIVER, "org.h2.Driver" )
+ .setProperty( Environment.URL, "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" )
+ .setProperty( Environment.USER, "sa" )
+ .setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ cfg.addAuxiliaryDatabaseObject(
+ new SimpleAuxiliaryDatabaseObject(
+ generator.sqlCreateStrings( dialect )[0],
+ generator.sqlDropStrings( dialect )[0]
+ )
+ );
+
+ sessionFactory = (SessionFactoryImplementor) cfg.buildSessionFactory();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if ( sessionFactory != null ) {
+ sessionFactory.close();
+ }
+
+ super.tearDown();
+ }
+
+ public void testHiLoAlgorithm() {
+ SessionImpl session = (SessionImpl) sessionFactory.openSession();
+ session.beginTransaction();
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // initially sequence should be uninitialized
+ assertEquals( 0L, extractSequenceValue( session ) );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // historically the hilo generators skipped the initial block of values;
+ // so the first generated id value is maxlo + 1, here be 4
+ Long generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 4L, generatedValue.longValue() );
+ // which should also perform the first read on the sequence which should set it to its "start with" value (1)
+ assertEquals( 1L, extractSequenceValue( session ) );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 5L, generatedValue.longValue() );
+ assertEquals( 1L, extractSequenceValue( session ) );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 6L, generatedValue.longValue() );
+ assertEquals( 1L, extractSequenceValue( session ) );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 7L, generatedValue.longValue() );
+ // unlike the newer strategies, the db value will not get update here. It gets updated on the next invocation
+ // after a clock over
+ assertEquals( 1L, extractSequenceValue( session ) );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 8L, generatedValue.longValue() );
+ // this should force an increment in the sequence value
+ assertEquals( 2L, extractSequenceValue( session ) );
+
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ private long extractSequenceValue(Session session) {
+ class WorkImpl implements Work {
+ private long value;
+ public void execute(Connection connection) throws SQLException {
+ PreparedStatement query = connection.prepareStatement( "select currval('" + TEST_SEQUENCE + "');" );
+ ResultSet resultSet = query.executeQuery();
+ resultSet.next();
+ value = resultSet.getLong( 1 );
+ }
+ }
+ WorkImpl work = new WorkImpl();
+ session.doWork( work );
+ return work.value;
+ }
+}
Modified: core/trunk/parent/pom.xml
===================================================================
--- core/trunk/parent/pom.xml 2010-05-11 19:24:54 UTC (rev 19469)
+++ core/trunk/parent/pom.xml 2010-05-11 19:27:20 UTC (rev 19470)
@@ -593,6 +593,7 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.134</version>
+ <scope>test</scope>
</dependency>
</dependencies>
<properties>
@@ -738,6 +739,7 @@
<groupId>com.ibm</groupId>
<artifactId>db2jcc_license_cu</artifactId>
<version>3.1.57</version>
+ <scope>test</scope>
</dependency>
</dependencies>
<properties>
@@ -764,6 +766,7 @@
<groupId>com.ibm</groupId>
<artifactId>db2jcc_license_cu</artifactId>
<version>3.8.47</version>
+ <scope>test</scope>
</dependency>
</dependencies>
<properties>
@@ -790,6 +793,7 @@
<groupId>com.ibm</groupId>
<artifactId>db2jcc_license_cu</artifactId>
<version>3.57.86</version>
+ <scope>test</scope>
</dependency>
</dependencies>
<properties>
14 years
Hibernate SVN: r19469 - in core/branches/Branch_3_5/core/src: main/java/org/hibernate/id/enhanced and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-05-11 15:24:54 -0400 (Tue, 11 May 2010)
New Revision: 19469
Added:
core/branches/Branch_3_5/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java
Modified:
core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceGenerator.java
core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
Log:
HHH-5042 - TableGenerator does not increment hibernate_sequences.next_hi_value anymore after having exhausted the current lo-range
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java 2010-05-11 18:44:39 UTC (rev 19468)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
@@ -37,6 +37,8 @@
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
+import org.hibernate.id.enhanced.AccessCallback;
+import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
@@ -62,7 +64,7 @@
* <p/>
* <p>This implementation is not compliant with a user connection</p>
* <p/>
- *
+ *
* <p>Allowed parameters (all of them are optional):</p>
* <ul>
* <li>table: table name (default <tt>hibernate_sequences</tt>)</li>
@@ -76,12 +78,12 @@
* @author Emmanuel Bernard
* @author <a href="mailto:kr@hbt.de">Klaus Richarz</a>.
*/
-public class MultipleHiLoPerTableGenerator
+public class MultipleHiLoPerTableGenerator
extends TransactionHelper
implements PersistentIdentifierGenerator, Configurable {
-
+
private static final Logger log = LoggerFactory.getLogger(MultipleHiLoPerTableGenerator.class);
-
+
public static final String ID_TABLE = "table";
public static final String PK_COLUMN_NAME = "primary_key_column";
public static final String PK_VALUE_NAME = "primary_key_value";
@@ -92,7 +94,7 @@
public static final String DEFAULT_TABLE = "hibernate_sequences";
private static final String DEFAULT_PK_COLUMN = "sequence_name";
private static final String DEFAULT_VALUE_COLUMN = "sequence_next_hi_value";
-
+
private String tableName;
private String pkColumnName;
private String valueColumnName;
@@ -104,8 +106,7 @@
public static final String MAX_LO = "max_lo";
private int maxLo;
- private int lo;
- private IntegralDataTypeHolder value;
+ private OptimizerFactory.LegacyHiLoAlgorithmOptimizer hiloOptimizer;
private Class returnClass;
private int keySize;
@@ -149,19 +150,15 @@
IntegralDataTypeHolder value = IdentifierGeneratorHelper.getIntegralDataTypeHolder( returnClass );
int rows;
do {
- // The loop ensures atomicity of the
- // select + update even for no transaction
- // or read committed isolation level
-
- //sql = query;
- SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
- PreparedStatement qps = conn.prepareStatement(query);
+ SQL_STATEMENT_LOGGER.logStatement( query, FormatStyle.BASIC );
+ PreparedStatement qps = conn.prepareStatement( query );
PreparedStatement ips = null;
try {
ResultSet rs = qps.executeQuery();
boolean isInitialized = rs.next();
if ( !isInitialized ) {
value.initialize( 0 );
+ SQL_STATEMENT_LOGGER.logStatement( insert, FormatStyle.BASIC );
ips = conn.prepareStatement( insert );
value.bind( ips, 1 );
ips.execute();
@@ -182,7 +179,8 @@
qps.close();
}
- PreparedStatement ups = conn.prepareStatement(update);
+ SQL_STATEMENT_LOGGER.logStatement( update, FormatStyle.BASIC );
+ PreparedStatement ups = conn.prepareStatement( update );
try {
value.copy().increment().bind( ups, 1 );
value.bind( ups, 2 );
@@ -195,12 +193,12 @@
finally {
ups.close();
}
- }
- while (rows==0);
+ } while ( rows==0 );
+
return value;
}
- public synchronized Serializable generate(SessionImplementor session, Object obj)
+ public synchronized Serializable generate(final SessionImplementor session, Object obj)
throws HibernateException {
// maxLo < 1 indicates a hilo generator with no hilo :?
if ( maxLo < 1 ) {
@@ -212,15 +210,13 @@
return value.makeValue();
}
- if ( lo > maxLo ) {
- IntegralDataTypeHolder hiVal = (IntegralDataTypeHolder) doWorkInNewTransaction( session );
- lo = ( hiVal.eq( 0 ) ) ? 1 : 0;
- value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo );
- if ( log.isDebugEnabled() ) {
- log.debug("new hi value: " + hiVal);
- }
- }
- return value.makeValueThenIncrement();
+ return hiloOptimizer.generate(
+ new AccessCallback() {
+ public IntegralDataTypeHolder getNextValue() {
+ return (IntegralDataTypeHolder) doWorkInNewTransaction( session );
+ }
+ }
+ );
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
@@ -270,10 +266,10 @@
valueColumnName +
" = ? and " +
pkColumnName +
- " = '" +
- keyValue
+ " = '" +
+ keyValue
+ "'";
-
+
insert = "insert into " + tableName +
"(" + pkColumnName + ", " + valueColumnName + ") " +
"values('"+ keyValue +"', ?)";
@@ -281,7 +277,8 @@
//hilo config
maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
- lo = maxLo + 1; // so we "clock over" on the first invocation
returnClass = type.getReturnedClass();
+
+ hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer( returnClass, maxLo );
}
}
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceGenerator.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceGenerator.java 2010-05-11 18:44:39 UTC (rev 19468)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
@@ -72,6 +72,10 @@
private Type identifierType;
private String sql;
+ public Type getIdentifierType() {
+ return identifierType;
+ }
+
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
sequenceName = normalizer.normalizeIdentifierQuoting(
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java 2010-05-11 18:44:39 UTC (rev 19468)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/SequenceHiLoGenerator.java 2010-05-11 19:24:54 UTC (rev 19469)
@@ -26,11 +26,11 @@
import java.io.Serializable;
import java.util.Properties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.id.enhanced.AccessCallback;
+import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.type.Type;
import org.hibernate.util.PropertiesHelper;
@@ -50,23 +50,24 @@
* @author Gavin King
*/
public class SequenceHiLoGenerator extends SequenceGenerator {
-
public static final String MAX_LO = "max_lo";
- private static final Logger log = LoggerFactory.getLogger(SequenceHiLoGenerator.class);
-
private int maxLo;
- private int lo;
- private IntegralDataTypeHolder value;
+ private OptimizerFactory.LegacyHiLoAlgorithmOptimizer hiloOptimizer;
public void configure(Type type, Properties params, Dialect d) throws MappingException {
super.configure(type, params, d);
- maxLo = PropertiesHelper.getInt(MAX_LO, params, 9);
- lo = maxLo + 1; // so we "clock over" on the first invocation
+
+ maxLo = PropertiesHelper.getInt( MAX_LO, params, 9 );
+
+ hiloOptimizer = new OptimizerFactory.LegacyHiLoAlgorithmOptimizer(
+ getIdentifierType().getReturnedClass(),
+ maxLo
+ );
}
- public synchronized Serializable generate(SessionImplementor session, Object obj) {
+ public synchronized Serializable generate(final SessionImplementor session, Object obj) {
// maxLo < 1 indicates a hilo generator with no hilo :?
if ( maxLo < 1 ) {
//keep the behavior consistent even for boundary usages
@@ -77,16 +78,16 @@
return value.makeValue();
}
- if ( lo > maxLo ) {
- IntegralDataTypeHolder hiVal = generateHolder( session );
- lo = ( hiVal.eq( 0 ) ) ? 1 : 0;
- value = hiVal.copy().multiplyBy( maxLo+1 ).add( lo );
- if ( log.isDebugEnabled() ) {
- log.debug("new hi value: " + hiVal);
- }
- }
+ return hiloOptimizer.generate(
+ new AccessCallback() {
+ public IntegralDataTypeHolder getNextValue() {
+ return generateHolder( session );
+ }
+ }
+ );
+ }
- return value.makeValueThenIncrement();
+ public OptimizerFactory.LegacyHiLoAlgorithmOptimizer getHiloOptimizer() {
+ return hiloOptimizer;
}
-
}
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-11 18:44:39 UTC (rev 19468)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/id/enhanced/OptimizerFactory.java 2010-05-11 19:24:54 UTC (rev 19469)
@@ -265,6 +265,67 @@
}
}
+ public static class LegacyHiLoAlgorithmOptimizer extends OptimizerSupport {
+ private long maxLo;
+ private long lo;
+ private IntegralDataTypeHolder hi;
+
+ private IntegralDataTypeHolder lastSourceValue;
+ private IntegralDataTypeHolder value;
+
+
+ public LegacyHiLoAlgorithmOptimizer(Class returnClass, int incrementSize) {
+ super( returnClass, incrementSize );
+ if ( incrementSize < 1 ) {
+ throw new HibernateException( "increment size cannot be less than 1" );
+ }
+ if ( log.isTraceEnabled() ) {
+ log.trace( "creating hilo optimizer (legacy) with [incrementSize=" + incrementSize + "; returnClass=" + returnClass.getName() + "]" );
+ }
+
+ maxLo = incrementSize;
+ lo = maxLo+1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized Serializable generate(AccessCallback callback) {
+ if ( lo > maxLo ) {
+ lastSourceValue = callback.getNextValue();
+ lo = lastSourceValue.eq( 0 ) ? 1 : 0;
+ hi = lastSourceValue.copy().multiplyBy( maxLo+1 );
+ }
+ value = hi.copy().add( lo++ );
+ return value.makeValue();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IntegralDataTypeHolder getLastSourceValue() {
+ return lastSourceValue.copy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean applyIncrementSizeToSourceValues() {
+ return false;
+ }
+
+ /**
+ * Getter for property 'lastValue'.
+ * <p/>
+ * Exposure intended for testing purposes.
+ *
+ * @return Value for property 'lastValue'.
+ */
+ public IntegralDataTypeHolder getLastValue() {
+ return value;
+ }
+ }
+
/**
* Optimizer which uses a pool of values, storing the next low value of the
* range in the database.
Added: core/branches/Branch_3_5/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java
===================================================================
--- core/branches/Branch_3_5/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java (rev 0)
+++ core/branches/Branch_3_5/core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java 2010-05-11 19:24:54 UTC (rev 19469)
@@ -0,0 +1,148 @@
+/*
+ * 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.id;
+
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.hibernate.Hibernate;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.ObjectNameNormalizer;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.mapping.SimpleAuxiliaryDatabaseObject;
+
+/**
+ * I went back to 3.3 source and grabbed the code/logic as it existed back then and crafted this
+ * unit test so that we can make sure the value keep being generated in the expected manner
+ *
+ * @author Steve Ebersole
+ */
+public class SequenceHiLoGeneratorTest extends TestCase {
+ private static final String TEST_SEQUENCE = "test_sequence";
+
+ private Configuration cfg;
+ private SessionFactoryImplementor sessionFactory;
+ private SequenceHiLoGenerator generator;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Properties properties = new Properties();
+ properties.setProperty( SequenceGenerator.SEQUENCE, TEST_SEQUENCE );
+ properties.setProperty( SequenceHiLoGenerator.MAX_LO, "3" );
+ properties.setProperty( SequenceGenerator.PARAMETERS, "start with 1" ); // hsqldb sequences start with 0 by default :?
+ properties.put(
+ PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
+ new ObjectNameNormalizer() {
+ protected boolean isUseQuotedIdentifiersGlobally() {
+ return false;
+ }
+
+ protected NamingStrategy getNamingStrategy() {
+ return cfg.getNamingStrategy();
+ }
+ }
+ );
+
+ Dialect dialect = new HSQLDialect();
+
+ generator = new SequenceHiLoGenerator();
+ //noinspection deprecation
+ generator.configure( Hibernate.LONG, properties, dialect );
+
+ cfg = new Configuration()
+ .setProperty( Environment.DRIVER, "org.hsqldb.jdbcDriver" )
+ .setProperty( Environment.URL, "jdbc:hsqldb:." )
+ .setProperty( Environment.USER, "sa" )
+ .setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ cfg.addAuxiliaryDatabaseObject(
+ new SimpleAuxiliaryDatabaseObject(
+ generator.sqlCreateStrings( dialect )[0],
+ generator.sqlDropStrings( dialect )[0]
+ )
+ );
+
+ sessionFactory = (SessionFactoryImplementor) cfg.buildSessionFactory();
+ }
+
+ protected void tearDown() throws Exception {
+ if ( sessionFactory != null ) {
+ sessionFactory.close();
+ }
+
+ super.tearDown();
+ }
+
+ public void testHiLoAlgorithm() {
+ SessionImpl session = (SessionImpl) sessionFactory.openSession();
+ session.beginTransaction();
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // initially sequence should be uninitialized
+// assertEquals( 1L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+// we have to assume here since in this branch we are testing with hsqldb which does not allow access to the
+// current sequence value and the optimizer does not yet know the value. On trunk (3.6), against H2, we physically
+// check the sequence value in the database
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // historically the hilo generators skipped the initial block of values;
+ // so the first generated id value is maxlo + 1, here be 4
+ Long generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 4L, generatedValue.longValue() );
+ // which should also perform the first read on the sequence which should set it to its "start with" value (1)
+ assertEquals( 1L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 5L, generatedValue.longValue() );
+ assertEquals( 1L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 6L, generatedValue.longValue() );
+ assertEquals( 1L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 7L, generatedValue.longValue() );
+ // unlike the newer strategies, the db value will not get update here. It gets updated on the next invocation
+ // after a clock over
+ assertEquals( 1L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ generatedValue = (Long) generator.generate( session, null );
+ assertEquals( 8L, generatedValue.longValue() );
+ // this should force an increment in the sequence value
+ assertEquals( 2L, generator.getHiloOptimizer().getLastSourceValue().makeValue().longValue() );
+
+ session.getTransaction().commit();
+ session.close();
+ }
+}
14 years
Hibernate SVN: r19468 - in search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test: worker and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: stliu
Date: 2010-05-11 14:44:39 -0400 (Tue, 11 May 2010)
New Revision: 19468
Modified:
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/SearchTestCase.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/TestCase.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/worker/WorkerTestCase.java
Log:
JBPAPP-4289 HSEARCH-496 h-search test locks
Modified: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/SearchTestCase.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-05-11 15:08:54 UTC (rev 19467)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-05-11 18:44:39 UTC (rev 19468)
@@ -50,6 +50,7 @@
}
protected void tearDown() throws Exception {
+ super.tearDown();
SchemaExport export = new SchemaExport( cfg );
export.drop( false, true );
}
Modified: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/TestCase.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/TestCase.java 2010-05-11 15:08:54 UTC (rev 19467)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/TestCase.java 2010-05-11 18:44:39 UTC (rev 19468)
@@ -2,6 +2,8 @@
package org.hibernate.search.test;
import java.io.InputStream;
+import java.sql.Connection;
+import java.sql.SQLException;
import org.apache.lucene.analysis.StopAnalyzer;
@@ -15,6 +17,7 @@
import org.hibernate.dialect.Dialect;
import org.hibernate.event.FlushEventListener;
import org.hibernate.event.def.DefaultFlushEventListener;
+import org.hibernate.jdbc.Work;
import org.hibernate.search.event.FullTextIndexEventListener;
/**
@@ -68,13 +71,27 @@
lastTestClass = getClass();
}
}
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if ( sessions != null ) {
+ sessions.close();
+ sessions = null;
+ }
+ }
+
+ private class RollbackWork implements Work{
+ public void execute( Connection connection ) throws SQLException {
+ connection.rollback();
+ }
+
+ }
protected void runTest() throws Throwable {
try {
super.runTest();
if ( session != null && session.isOpen() ) {
if ( session.isConnected() ) {
- session.connection().rollback();
+ session.doWork( new RollbackWork() );
}
session.close();
session = null;
@@ -88,7 +105,7 @@
try {
if ( session != null && session.isOpen() ) {
if ( session.isConnected() ) {
- session.connection().rollback();
+ session.doWork( new RollbackWork() );
}
session.close();
}
Modified: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/worker/WorkerTestCase.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/worker/WorkerTestCase.java 2010-05-11 15:08:54 UTC (rev 19467)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/worker/WorkerTestCase.java 2010-05-11 18:44:39 UTC (rev 19468)
@@ -4,6 +4,7 @@
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.analysis.StopAnalyzer;
import org.apache.lucene.queryParser.ParseException;
@@ -54,7 +55,7 @@
es.execute( work );
es.execute( reverseWork );
}
- while ( work.count < iteration - 1 ) {
+ while ( work.count.get() < iteration - 1 ) {
Thread.sleep( 20 );
}
getSessions().close();
@@ -64,66 +65,75 @@
protected static class Work implements Runnable {
private SessionFactory sf;
- public volatile int count = 0;
+ public AtomicInteger count = new AtomicInteger(0);
public Work(SessionFactory sf) {
this.sf = sf;
}
public void run() {
- Session s = sf.openSession();
- Transaction tx = s.beginTransaction();
- Employee ee = new Employee();
- ee.setName( "Emmanuel" );
- s.persist( ee );
- Employer er = new Employer();
- er.setName( "RH" );
- s.persist( er );
- tx.commit();
- s.close();
+ Session s = null;
+ Transaction tx = null;
+ try {
+ s = sf.openSession();
+ tx = s.beginTransaction();
+ Employee ee = new Employee();
+ ee.setName( "Emmanuel" );
+ s.persist( ee );
+ Employer er = new Employer();
+ er.setName( "RH" );
+ s.persist( er );
+ tx.commit();
+ s.close();
- s = sf.openSession();
- tx = s.beginTransaction();
- ee = (Employee) s.get( Employee.class, ee.getId() );
- ee.setName( "Emmanuel2" );
- er = (Employer) s.get( Employer.class, er.getId() );
- er.setName( "RH2" );
- tx.commit();
- s.close();
+ s = sf.openSession();
+ tx = s.beginTransaction();
+ ee = (Employee) s.get( Employee.class, ee.getId() );
+ ee.setName( "Emmanuel2" );
+ er = (Employer) s.get( Employer.class, er.getId() );
+ er.setName( "RH2" );
+ tx.commit();
+ s.close();
-// try {
-// Thread.sleep( 50 );
-// }
-// catch (InterruptedException e) {
-// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
-// }
+ s = sf.openSession();
+ tx = s.beginTransaction();
+ FullTextSession fts = new FullTextSessionImpl( s );
+ QueryParser parser = new QueryParser( "id", new StopAnalyzer() );
+ Query query;
+ try {
+ query = parser.parse( "name:emmanuel2" );
+ }
+ catch (ParseException e) {
+ throw new RuntimeException( e );
+ }
+ boolean results = fts.createFullTextQuery( query ).list().size() > 0;
+ //don't test because in case of async, it query happens before actual saving
+ //if ( !results ) throw new RuntimeException( "No results!" );
+ tx.commit();
+ s.close();
- s = sf.openSession();
- tx = s.beginTransaction();
- FullTextSession fts = new FullTextSessionImpl( s );
- QueryParser parser = new QueryParser( "id", new StopAnalyzer() );
- Query query;
- try {
- query = parser.parse( "name:emmanuel2" );
+ s = sf.openSession();
+ tx = s.beginTransaction();
+ ee = (Employee) s.get( Employee.class, ee.getId() );
+ s.delete( ee );
+ er = (Employer) s.get( Employer.class, er.getId() );
+ s.delete( er );
+ tx.commit();
+ s.close();
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ } finally {
+ count.incrementAndGet();
+ try {
+ if ( tx != null && tx.isActive() )
+ tx.rollback();
+ if ( s != null && s.isOpen() )
+ s.close();
+ } catch ( Throwable t ) {
+ t.printStackTrace();
+ }
}
- catch (ParseException e) {
- throw new RuntimeException( e );
- }
- boolean results = fts.createFullTextQuery( query ).list().size() > 0;
- //don't test because in case of async, it query happens before actual saving
- //if ( !results ) throw new RuntimeException( "No results!" );
- tx.commit();
- s.close();
-
- s = sf.openSession();
- tx = s.beginTransaction();
- ee = (Employee) s.get( Employee.class, ee.getId() );
- s.delete( ee );
- er = (Employer) s.get( Employer.class, er.getId() );
- s.delete( er );
- tx.commit();
- s.close();
- count++;
+
}
}
@@ -172,6 +182,8 @@
cfg.setProperty( "hibernate.search.default.indexBase", sub.getAbsolutePath() );
cfg.setProperty( "hibernate.search.Clock.directory_provider", FSDirectoryProvider.class.getName() );
cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
+ cfg.setProperty( "hibernate.show_sql", "false" );
+ cfg.setProperty( "hibernate.format_sql", "false" );
}
@SuppressWarnings("unchecked")
14 years
Hibernate SVN: r19467 - in core/trunk/entitymanager/src: main/java/org/hibernate/ejb/criteria/expression and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-05-11 11:08:54 -0400 (Tue, 11 May 2010)
New Revision: 19467
Modified:
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java
core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java
core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java
Log:
HHH-4966 - Entity Manager bug with ParameterExpressionImpl
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java 2010-05-11 15:08:10 UTC (rev 19466)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java 2010-05-11 15:08:54 UTC (rev 19467)
@@ -100,26 +100,23 @@
public String generateAlias();
/**
- * Generate a name for a parameter into the JPAQL query.
- *
- * @return The generated para name
- */
- public String generateParameterName();
-
- /**
* Register parameters explicitly encountered in the criteria query.
*
* @param criteriaQueryParameter The parameter expression
- * @param jpaqlParameterName The generated name for the parameter
+ *
+ * @return The JPA-QL parameter name
*/
- public void registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter, String jpaqlParameterName);
+ public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
/**
* Register a parameter that was not part of the criteria query (at least not as a parameter).
*
- * @param binding The parameter description.
+ * @param literal The literal value
+ * @param javaType The java type as whcih to handle the literal value.
+ *
+ * @return The JPA-QL parameter name
*/
- public void registerImplicitParameterBinding(ImplicitParameterBinding binding);
+ public String registerLiteralParameterBinding(Object literal, Class javaType);
/**
* Given a java type, determine the proper cast type name.
@@ -164,22 +161,43 @@
return "param" + explicitParameterCount++;
}
- public void registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter, String jpaqlParameterName) {
- explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
+ public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter) {
+ final String jpaqlParameterName;
+ if ( explicitParameterMapping.containsKey( criteriaQueryParameter ) ) {
+ jpaqlParameterName = explicitParameterMapping.get( criteriaQueryParameter );
+ }
+ else {
+ jpaqlParameterName = generateParameterName();
+ explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
+ }
if ( StringHelper.isNotEmpty( criteriaQueryParameter.getName() ) ) {
explicitParameterNameMapping.put(
criteriaQueryParameter.getName(),
criteriaQueryParameter
);
}
+ return jpaqlParameterName;
}
- public void registerImplicitParameterBinding(ImplicitParameterBinding binding) {
+ public String registerLiteralParameterBinding(final Object literal, final Class javaType) {
+ final String parameterName = generateParameterName();
+ final ImplicitParameterBinding binding = new CriteriaQueryCompiler.ImplicitParameterBinding() {
+ public String getParameterName() {
+ return parameterName;
+ }
+
+ public Class getJavaType() {
+ return javaType;
+ }
+
+ public void bind(TypedQuery typedQuery) {
+ typedQuery.setParameter( parameterName, literal );
+ }
+ };
+
implicitParameterBindings.add( binding );
- implicitParameterTypes.put(
- binding.getParameterName(),
- binding.getJavaType()
- );
+ implicitParameterTypes.put( parameterName, javaType );
+ return parameterName;
}
public String getCastType(Class javaType) {
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java 2010-05-11 15:08:10 UTC (rev 19466)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java 2010-05-11 15:08:54 UTC (rev 19467)
@@ -69,22 +69,7 @@
}
// else...
- final String parameterName = renderingContext.generateParameterName();
- renderingContext.registerImplicitParameterBinding(
- new CriteriaQueryCompiler.ImplicitParameterBinding() {
- public String getParameterName() {
- return parameterName;
- }
-
- public Class getJavaType() {
- return LiteralExpression.this.getJavaType();
- }
-
- public void bind(TypedQuery typedQuery) {
- typedQuery.setParameter( parameterName, getLiteral() );
- }
- }
- );
+ final String parameterName = renderingContext.registerLiteralParameterBinding( getLiteral(), getJavaType() );
return ':' + parameterName;
}
Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java 2010-05-11 15:08:10 UTC (rev 19466)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java 2010-05-11 15:08:54 UTC (rev 19467)
@@ -85,8 +85,7 @@
}
public String render(CriteriaQueryCompiler.RenderingContext renderingContext) {
- final String jpaqlParamName = renderingContext.generateParameterName();
- renderingContext.registerExplicitParameter( this, jpaqlParamName );
+ final String jpaqlParamName = renderingContext.registerExplicitParameter( this );
return ':' + jpaqlParamName;
}
Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java 2010-05-11 15:08:10 UTC (rev 19466)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java 2010-05-11 15:08:54 UTC (rev 19467)
@@ -27,11 +27,18 @@
import java.math.BigInteger;
import java.util.List;
import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import org.hibernate.Query;
import org.hibernate.ejb.metamodel.AbstractMetamodelSpecificTest;
import org.hibernate.ejb.metamodel.Product;
+import org.hibernate.ejb.metamodel.Product_;
+import org.hibernate.impl.AbstractQueryImpl;
/**
* Tests that various expressions operate as expected
@@ -60,16 +67,6 @@
em.close();
}
- @Override
- public void tearDown() throws Exception {
- EntityManager em = getOrCreateEntityManager();
- em.getTransaction().begin();
- em.createQuery( "delete Product" ).executeUpdate();
- em.getTransaction().commit();
- em.close();
- super.tearDown();
- }
-
public void testEmptyConjunction() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
@@ -227,4 +224,28 @@
em.close();
}
+
+ public void testParameterReuse() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ CriteriaQuery<Product> criteria = em.getCriteriaBuilder().createQuery( Product.class );
+ Root<Product> from = criteria.from( Product.class );
+ ParameterExpression<String> param = em.getCriteriaBuilder().parameter( String.class );
+ Predicate predicate = em.getCriteriaBuilder().equal( from.get( Product_.id ), param );
+ Predicate predicate2 = em.getCriteriaBuilder().equal( from.get( Product_.name ), param );
+ criteria.where( em.getCriteriaBuilder().or( predicate, predicate2 ) );
+ assertEquals( 1, criteria.getParameters().size() );
+ TypedQuery<Product> query = em.createQuery( criteria );
+ int hqlParamCount = countGeneratedParameters( query.unwrap( Query.class ) );
+ assertEquals( 1, hqlParamCount );
+ query.setParameter( param, "abc" ).getResultList();
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ private int countGeneratedParameters(Query query) {
+ AbstractQueryImpl hqlQueryImpl = (AbstractQueryImpl) query;
+ return hqlQueryImpl.getParameterMetadata().getNamedParameterNames().size();
+ }
+
}
14 years
Hibernate SVN: r19466 - in core/branches/Branch_3_5/entitymanager/src: main/java/org/hibernate/ejb/criteria/expression and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-05-11 11:08:10 -0400 (Tue, 11 May 2010)
New Revision: 19466
Modified:
core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java
core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java
core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/QueryBuilderTest.java
core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java
Log:
HHH-4966 - Entity Manager bug with ParameterExpressionImpl
Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java 2010-05-11 09:39:54 UTC (rev 19465)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java 2010-05-11 15:08:10 UTC (rev 19466)
@@ -100,26 +100,23 @@
public String generateAlias();
/**
- * Generate a name for a parameter into the JPAQL query.
- *
- * @return The generated para name
- */
- public String generateParameterName();
-
- /**
* Register parameters explicitly encountered in the criteria query.
*
* @param criteriaQueryParameter The parameter expression
- * @param jpaqlParameterName The generated name for the parameter
+ *
+ * @return The JPA-QL parameter name
*/
- public void registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter, String jpaqlParameterName);
+ public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
/**
* Register a parameter that was not part of the criteria query (at least not as a parameter).
*
- * @param binding The parameter description.
+ * @param literal The literal value
+ * @param javaType The java type as whcih to handle the literal value.
+ *
+ * @return The JPA-QL parameter name
*/
- public void registerImplicitParameterBinding(ImplicitParameterBinding binding);
+ public String registerLiteralParameterBinding(Object literal, Class javaType);
/**
* Given a java type, determine the proper cast type name.
@@ -164,22 +161,43 @@
return "param" + explicitParameterCount++;
}
- public void registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter, String jpaqlParameterName) {
- explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
+ public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter) {
+ final String jpaqlParameterName;
+ if ( explicitParameterMapping.containsKey( criteriaQueryParameter ) ) {
+ jpaqlParameterName = explicitParameterMapping.get( criteriaQueryParameter );
+ }
+ else {
+ jpaqlParameterName = generateParameterName();
+ explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
+ }
if ( StringHelper.isNotEmpty( criteriaQueryParameter.getName() ) ) {
explicitParameterNameMapping.put(
criteriaQueryParameter.getName(),
criteriaQueryParameter
);
}
+ return jpaqlParameterName;
}
- public void registerImplicitParameterBinding(ImplicitParameterBinding binding) {
+ public String registerLiteralParameterBinding(final Object literal, final Class javaType) {
+ final String parameterName = generateParameterName();
+ final ImplicitParameterBinding binding = new CriteriaQueryCompiler.ImplicitParameterBinding() {
+ public String getParameterName() {
+ return parameterName;
+ }
+
+ public Class getJavaType() {
+ return javaType;
+ }
+
+ public void bind(TypedQuery typedQuery) {
+ typedQuery.setParameter( parameterName, literal );
+ }
+ };
+
implicitParameterBindings.add( binding );
- implicitParameterTypes.put(
- binding.getParameterName(),
- binding.getJavaType()
- );
+ implicitParameterTypes.put( parameterName, javaType );
+ return parameterName;
}
public String getCastType(Class javaType) {
Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java 2010-05-11 09:39:54 UTC (rev 19465)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/LiteralExpression.java 2010-05-11 15:08:10 UTC (rev 19466)
@@ -69,22 +69,7 @@
}
// else...
- final String parameterName = renderingContext.generateParameterName();
- renderingContext.registerImplicitParameterBinding(
- new CriteriaQueryCompiler.ImplicitParameterBinding() {
- public String getParameterName() {
- return parameterName;
- }
-
- public Class getJavaType() {
- return LiteralExpression.this.getJavaType();
- }
-
- public void bind(TypedQuery typedQuery) {
- typedQuery.setParameter( parameterName, getLiteral() );
- }
- }
- );
+ final String parameterName = renderingContext.registerLiteralParameterBinding( getLiteral(), getJavaType() );
return ':' + parameterName;
}
Modified: core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java 2010-05-11 09:39:54 UTC (rev 19465)
+++ core/branches/Branch_3_5/entitymanager/src/main/java/org/hibernate/ejb/criteria/expression/ParameterExpressionImpl.java 2010-05-11 15:08:10 UTC (rev 19466)
@@ -85,8 +85,7 @@
}
public String render(CriteriaQueryCompiler.RenderingContext renderingContext) {
- final String jpaqlParamName = renderingContext.generateParameterName();
- renderingContext.registerExplicitParameter( this, jpaqlParamName );
+ final String jpaqlParamName = renderingContext.registerExplicitParameter( this );
return ':' + jpaqlParamName;
}
Modified: core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/QueryBuilderTest.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/QueryBuilderTest.java 2010-05-11 09:39:54 UTC (rev 19465)
+++ core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/QueryBuilderTest.java 2010-05-11 15:08:10 UTC (rev 19466)
@@ -26,14 +26,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
-import javax.persistence.metamodel.PluralAttribute;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.hibernate.ejb.metamodel.Address;
@@ -41,11 +38,10 @@
import org.hibernate.ejb.metamodel.Country;
import org.hibernate.ejb.metamodel.CreditCard;
import org.hibernate.ejb.metamodel.Customer;
-import org.hibernate.ejb.metamodel.Customer_;
import org.hibernate.ejb.metamodel.Info;
import org.hibernate.ejb.metamodel.LineItem;
-import org.hibernate.ejb.metamodel.Order;
import org.hibernate.ejb.metamodel.MetamodelImpl;
+import org.hibernate.ejb.metamodel.Order;
import org.hibernate.ejb.metamodel.Phone;
import org.hibernate.ejb.metamodel.Product;
import org.hibernate.ejb.metamodel.ShelfLife;
Modified: core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java
===================================================================
--- core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java 2010-05-11 09:39:54 UTC (rev 19465)
+++ core/branches/Branch_3_5/entitymanager/src/test/java/org/hibernate/ejb/criteria/basic/ExpressionsTest.java 2010-05-11 15:08:10 UTC (rev 19466)
@@ -27,11 +27,18 @@
import java.math.BigInteger;
import java.util.List;
import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import org.hibernate.Query;
import org.hibernate.ejb.metamodel.AbstractMetamodelSpecificTest;
import org.hibernate.ejb.metamodel.Product;
+import org.hibernate.ejb.metamodel.Product_;
+import org.hibernate.impl.AbstractQueryImpl;
/**
* Tests that various expressions operate as expected
@@ -45,7 +52,7 @@
public void setUp() throws Exception {
super.setUp();
builder = factory.getCriteriaBuilder();
- EntityManager em = getOrCreateEntityManager();
+ EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
Product product = new Product();
product.setId( "product1" );
@@ -60,16 +67,6 @@
em.close();
}
- @Override
- public void tearDown() throws Exception {
- EntityManager em = getOrCreateEntityManager();
- em.getTransaction().begin();
- em.createQuery( "delete Product" ).executeUpdate();
- em.getTransaction().commit();
- em.close();
- super.tearDown();
- }
-
public void testEmptyConjunction() {
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
@@ -227,4 +224,26 @@
em.close();
}
+ public void testParameterReuse() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ CriteriaQuery<Product> criteria = em.getCriteriaBuilder().createQuery( Product.class );
+ Root<Product> from = criteria.from( Product.class );
+ ParameterExpression<String> param = em.getCriteriaBuilder().parameter( String.class );
+ Predicate predicate = em.getCriteriaBuilder().equal( from.get( Product_.id ), param );
+ Predicate predicate2 = em.getCriteriaBuilder().equal( from.get( Product_.name ), param );
+ criteria.where( em.getCriteriaBuilder().or( predicate, predicate2 ) );
+ assertEquals( 1, criteria.getParameters().size() );
+ TypedQuery<Product> query = em.createQuery( criteria );
+ int hqlParamCount = countGeneratedParameters( query.unwrap( Query.class ) );
+ assertEquals( 1, hqlParamCount );
+ query.setParameter( param, "abc" ).getResultList();
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ private int countGeneratedParameters(Query query) {
+ AbstractQueryImpl hqlQueryImpl = (AbstractQueryImpl) query;
+ return hqlQueryImpl.getParameterMetadata().getNamedParameterNames().size();
+ }
}
14 years
Hibernate SVN: r19465 - in search/branches/v3_1_1_GA_CP/src: main/java/org/hibernate/search/engine and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: stliu
Date: 2010-05-11 05:39:54 -0400 (Tue, 11 May 2010)
New Revision: 19465
Added:
search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/annotations/DynamicBoost.java
search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/BoostStrategy.java
search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DefaultBoostStrategy.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomBoostStrategy.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomFieldBoostStrategy.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostedDescriptionLibrary.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostingTest.java
Modified:
search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java
search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/FieldBoostTest.java
Log:
JBPAPP-4279 Hibernate Search @DynamicBoost feature back port
Added: search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/annotations/DynamicBoost.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/annotations/DynamicBoost.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/annotations/DynamicBoost.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,52 @@
+/* $Id: DynamicBoost.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.hibernate.search.engine.BoostStrategy;
+
+/**
+ * Apply a dynamic boost factor on a field or a whole entity.
+ *
+ * @author Hardy Ferentschik
+ */
+(a)Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })
+@Documented
+public @interface DynamicBoost {
+
+ /**
+ * @return An implementation of <code>BoostStrategy</code> to apply a boost
+ * value as function of the annotated object.
+ *
+ * @see org.hibernate.search.engine.BoostStrategy
+ */
+ public abstract Class<? extends BoostStrategy> impl();
+}
Added: search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/BoostStrategy.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/BoostStrategy.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/BoostStrategy.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,37 @@
+/* $Id: BoostStrategy.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.engine;
+
+/**
+ * Interface to implement boost values as functions
+ * of the object value being boosted.
+ * Implementations must be threadsafe.
+ *
+ * @author Hardy Ferentschik
+ * @see org.hibernate.search.annotations.Boost
+ */
+public interface BoostStrategy {
+ public float defineBoost(Object value);
+}
Added: search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DefaultBoostStrategy.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DefaultBoostStrategy.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DefaultBoostStrategy.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,35 @@
+/* $Id: DefaultBoostStrategy.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.engine;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class DefaultBoostStrategy implements BoostStrategy {
+
+ public float defineBoost(Object value) {
+ return 1.0f;
+ }
+}
Modified: search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java 2010-05-11 01:48:17 UTC (rev 19464)
+++ search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -35,6 +35,7 @@
import org.hibernate.search.annotations.ClassBridges;
import org.hibernate.search.annotations.ContainedIn;
import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.DynamicBoost;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;
@@ -99,6 +100,7 @@
protected void init(XClass clazz, InitContext context) {
metadata.boost = getBoost( clazz );
+ metadata.classBoostStrategy = getDynamicBoost( clazz );
metadata.analyzer = context.getDefaultAnalyzer();
Set<XClass> processedClasses = new HashSet<XClass>();
@@ -461,6 +463,7 @@
propertiesMetadata.fieldStore.add( getStore( fieldAnn.store() ) );
propertiesMetadata.fieldIndex.add( getIndex( fieldAnn.index() ) );
propertiesMetadata.fieldBoosts.add( getBoost( member, fieldAnn ) );
+ propertiesMetadata.dynamicFieldBoosts.add( getDynamicBoost( member ) );
propertiesMetadata.fieldTermVectors.add( getTermVector( fieldAnn.termVector() ) );
propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( fieldAnn, member, reflectionManager ) );
@@ -485,7 +488,24 @@
}
return computedBoost;
}
+ protected BoostStrategy getDynamicBoost(XProperty member) {
+ DynamicBoost boostAnnotation = member.getAnnotation( DynamicBoost.class );
+ if ( boostAnnotation == null ) {
+ return new DefaultBoostStrategy();
+ }
+ Class<? extends BoostStrategy> boostStrategyClass = boostAnnotation.impl();
+ BoostStrategy strategy;
+ try {
+ strategy = boostStrategyClass.newInstance();
+ }
+ catch ( Exception e ) {
+ throw new SearchException(
+ "Unable to instantiate boost strategy implementation: " + boostStrategyClass.getName()
+ );
+ }
+ return strategy;
+ }
private String buildEmbeddedPrefix(String prefix, IndexedEmbedded embeddedAnn, XProperty member) {
String localPrefix = prefix;
if ( ".".equals( embeddedAnn.prefix() ) ) {
@@ -544,13 +564,36 @@
}
protected Float getBoost(XClass element) {
+ float boost = 1.0f;
if ( element == null ) {
+ return boost;
+ }
+ Boost boostAnnotation = element.getAnnotation( Boost.class );
+ if( boostAnnotation != null ){
+ boost = boostAnnotation.value();
+ }
+ return boost;
+ }
+ protected BoostStrategy getDynamicBoost(XClass element) {
+ if ( element == null ) {
return null;
}
- Boost boost = element.getAnnotation( Boost.class );
- return boost != null ?
- boost.value() :
- null;
+ DynamicBoost boostAnnotation = element.getAnnotation( DynamicBoost.class );
+ if ( boostAnnotation == null ) {
+ return new DefaultBoostStrategy();
+ }
+
+ Class<? extends BoostStrategy> boostStrategyClass = boostAnnotation.impl();
+ BoostStrategy strategy;
+ try {
+ strategy = boostStrategyClass.newInstance();
+ }
+ catch ( Exception e ) {
+ throw new SearchException(
+ "Unable to instantiate boost strategy implementation: " + boostStrategyClass.getName()
+ );
+ }
+ return strategy;
}
//TODO could we use T instead of EntityClass?
@@ -673,19 +716,24 @@
}
/**
- * Wrapper class containing all the meta data extracted out of the entities.
+ * Wrapper class containing all the meta data extracted out of a single entity.
+ * All field/property related properties are kept in lists. Retrieving all metadata for a given
+ * property/field means accessing all the lists with the same index.
*/
protected static class PropertiesMetadata {
- public Float boost;
+ public float boost;
public Analyzer analyzer;
public Discriminator discriminator;
public XMember discriminatorGetter;
+ public BoostStrategy classBoostStrategy;
public final List<String> fieldNames = new ArrayList<String>();
public final List<XMember> fieldGetters = new ArrayList<XMember>();
public final List<FieldBridge> fieldBridges = new ArrayList<FieldBridge>();
public final List<Field.Store> fieldStore = new ArrayList<Field.Store>();
public final List<Field.Index> fieldIndex = new ArrayList<Field.Index>();
public final List<Float> fieldBoosts = new ArrayList<Float>();
+ public final List<BoostStrategy> dynamicFieldBoosts = new ArrayList<BoostStrategy>();
+
public final List<Field.TermVector> fieldTermVectors = new ArrayList<Field.TermVector>();
public final List<XMember> embeddedGetters = new ArrayList<XMember>();
public final List<PropertiesMetadata> embeddedPropertiesMetadata = new ArrayList<PropertiesMetadata>();
@@ -712,13 +760,19 @@
);
}
- protected LuceneOptions getFieldLuceneOptions(int i) {
+ protected LuceneOptions getFieldLuceneOptions(int i, Object value) {
LuceneOptions options;
options = new LuceneOptionsImpl(
fieldStore.get( i ),
- fieldIndex.get( i ), fieldTermVectors.get( i ), fieldBoosts.get( i )
+ fieldIndex.get( i ),
+ fieldTermVectors.get( i ),
+ fieldBoosts.get( i ) * dynamicFieldBoosts.get( i ).defineBoost( value )
);
return options;
}
+
+ protected float getClassBoost(Object value) {
+ return boost * classBoostStrategy.defineBoost( value );
+ }
}
}
\ No newline at end of file
Modified: search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2010-05-11 01:48:17 UTC (rev 19464)
+++ search/branches/v3_1_1_GA_CP/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -197,6 +197,7 @@
propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
+ propertiesMetadata.dynamicFieldBoosts.add( getDynamicBoost( member ) );
// property > entity analyzer (no field analyzer)
Analyzer analyzer = getAnalyzer( member, context );
if ( analyzer == null ) {
@@ -222,28 +223,33 @@
* @return the annotation used as document id or <code>null</code> if id annotation is specified on the property.
*/
private Annotation getIdAnnotation(XProperty member, InitContext context) {
+ Annotation idAnnotation = null;
+
// check for explicit DocumentId
- Annotation documentIdAnn = member.getAnnotation( DocumentId.class );
+ DocumentId documentIdAnn = member.getAnnotation( DocumentId.class );
if ( documentIdAnn != null ) {
explicitDocumentId = true;
- return documentIdAnn;
+ idAnnotation = documentIdAnn;
}
-
// check for JPA @Id
- if ( !explicitDocumentId && context.isJpaPresent() ) {
- Class idClass;
+ else if ( !explicitDocumentId && context.isJpaPresent() ) {
+ Annotation jpaId;
try {
- idClass = org.hibernate.util.ReflectHelper.classForName( "javax.persistence.Id", InitContext.class );
+ @SuppressWarnings("unchecked")
+ Class<? extends Annotation> jpaIdClass =
+ org.hibernate.annotations.common.util.ReflectHelper
+ .classForName( "javax.persistence.Id", InitContext.class );
+ jpaId = member.getAnnotation( jpaIdClass );
}
catch ( ClassNotFoundException e ) {
throw new SearchException( "Unable to load @Id.class even though it should be present ?!" );
}
- documentIdAnn = member.getAnnotation( idClass );
- if ( documentIdAnn != null ) {
+ if ( jpaId != null ) {
log.debug( "Found JPA id and using it as document id" );
+ idAnnotation = jpaId;
}
}
- return documentIdAnn;
+ return idAnnotation;
}
private ProvidedId findProvidedId(XClass clazz, ReflectionManager reflectionManager) {
@@ -353,10 +359,7 @@
Document doc = new Document();
final Class<?> entityType = Hibernate.getClass( instance );
- if ( metadata.boost != null ) {
- doc.setBoost( metadata.boost );
- }
-
+ doc.setBoost( metadata.getClassBoost( instance ) );
// add the class name of the entity to the document
Field classField =
new Field(
@@ -405,7 +408,7 @@
Object value = ReflectionHelper.getMemberValue( unproxiedInstance, member );
propertiesMetadata.fieldBridges.get( i ).set(
propertiesMetadata.fieldNames.get( i ), value, doc,
- propertiesMetadata.getFieldLuceneOptions( i )
+ propertiesMetadata.getFieldLuceneOptions( i, value )
);
}
Added: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomBoostStrategy.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomBoostStrategy.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomBoostStrategy.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,42 @@
+/* $Id: CustomBoostStrategy.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.test.query.boost;
+
+import org.hibernate.search.engine.BoostStrategy;
+
+/**
+ * Example for a custom <code>BoostStrategy</code> implementation.
+ *
+ * @author Sanne Grinovero
+ * @author Hardy Ferentschik
+ * @see org.hibernate.search.engine.BoostStrategy
+ */
+public class CustomBoostStrategy implements BoostStrategy {
+
+ public float defineBoost(Object value) {
+ DynamicBoostedDescriptionLibrary indexed = ( DynamicBoostedDescriptionLibrary ) value;
+ return indexed.getDynScore();
+ }
+}
Added: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomFieldBoostStrategy.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomFieldBoostStrategy.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/CustomFieldBoostStrategy.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,46 @@
+/* $Id: CustomFieldBoostStrategy.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.test.query.boost;
+
+import org.hibernate.search.engine.BoostStrategy;
+
+/**
+ * Example for a custom <code>BoostStrategy</code> implementation.
+ *
+ * @author Hardy Ferentschik
+ * @see org.hibernate.search.engine.BoostStrategy
+ */
+public class CustomFieldBoostStrategy implements BoostStrategy {
+
+ public float defineBoost(Object value) {
+ String name = ( String ) value;
+ if ( "foobar".equals( name ) ) {
+ return 3.0f;
+ }
+ else {
+ return 1.0f;
+ }
+ }
+}
Added: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostedDescriptionLibrary.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostedDescriptionLibrary.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostedDescriptionLibrary.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,87 @@
+/* $Id: DynamicBoostedDescriptionLibrary.java 19172 2010-04-06 09:17:34Z sannegrinovero $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.test.query.boost;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.Store;
+import org.hibernate.search.annotations.DynamicBoost;
+
+/**
+ * Test entity using a custom <code>CustomBoostStrategy</code> to set
+ * the document boost as the dynScore field.
+ *
+ * @author Sanne Grinovero
+ * @author Hardy Ferentschik
+ */
+@Entity
+@Indexed
+@DynamicBoost(impl = CustomBoostStrategy.class)
+@Table(name="DynBoostLibrary")
+public class DynamicBoostedDescriptionLibrary {
+
+ private int id;
+ private float dynScore;
+ private String name;
+
+ public DynamicBoostedDescriptionLibrary() {
+ dynScore = 1.0f;
+ }
+
+ @Id
+ @GeneratedValue
+ @DocumentId
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public float getDynScore() {
+ return dynScore;
+ }
+
+ public void setDynScore(float dynScore) {
+ this.dynScore = dynScore;
+ }
+
+ @Field(store = Store.YES)
+ @DynamicBoost(impl = CustomFieldBoostStrategy.class)
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Added: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostingTest.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostingTest.java (rev 0)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/DynamicBoostingTest.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -0,0 +1,132 @@
+/* $Id: DynamicBoostingTest.java 19002 2010-03-16 01:28:07Z hardy.ferentschik $
+ *
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.search.test.query.boost;
+
+import java.util.List;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.slf4j.Logger;
+
+import org.hibernate.Session;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.ProjectionConstants;
+import org.hibernate.search.Search;
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.util.LoggerFactory;
+
+public class DynamicBoostingTest extends SearchTestCase {
+
+ private static final Logger log = LoggerFactory.make();
+
+ public void testDynamicBoosts() throws Exception {
+
+ Session session = openSession();
+ session.beginTransaction();
+
+ DynamicBoostedDescriptionLibrary lib1 = new DynamicBoostedDescriptionLibrary();
+ lib1.setName( "one" );
+ session.persist( lib1 );
+
+ DynamicBoostedDescriptionLibrary lib2 = new DynamicBoostedDescriptionLibrary();
+ lib2.setName( "two" );
+ session.persist( lib2 );
+
+ session.getTransaction().commit();
+ session.close();
+
+ float lib1Score = getScore( new TermQuery( new Term( "name", "one" ) ) );
+ float lib2Score = getScore( new TermQuery( new Term( "name", "two" ) ) );
+ assertEquals( "The scores should be equal", lib1Score, lib2Score );
+
+ // set dynamic score and reindex!
+ session = openSession();
+ session.beginTransaction();
+
+ session.refresh( lib2 );
+ lib2.setDynScore( 2.0f );
+
+ session.getTransaction().commit();
+ session.close();
+
+ lib1Score = getScore( new TermQuery( new Term( "name", "one" ) ) );
+ lib2Score = getScore( new TermQuery( new Term( "name", "two" ) ) );
+ assertTrue( "lib2score should be greater than lib1score", lib1Score < lib2Score );
+
+
+
+ lib1Score = getScore( new TermQuery( new Term( "name", "foobar" ) ) );
+ assertEquals( "lib1score should be 0 since term is not yet indexed.", 0.0f, lib1Score );
+
+ // index foobar
+ session = openSession();
+ session.beginTransaction();
+
+ session.refresh( lib1 );
+ lib1.setName( "foobar" );
+
+ session.getTransaction().commit();
+ session.close();
+
+ lib1Score = getScore( new TermQuery( new Term( "name", "foobar" ) ) );
+ lib2Score = getScore( new TermQuery( new Term( "name", "two" ) ) );
+ assertTrue( "lib1score should be greater than lib2score", lib1Score > lib2Score );
+ }
+
+ private float getScore(Query query) {
+ Session session = openSession();
+ Object[] queryResult;
+ float score;
+ try {
+ FullTextSession fullTextSession = Search.getFullTextSession( session );
+ List resultList = fullTextSession
+ .createFullTextQuery( query, DynamicBoostedDescriptionLibrary.class )
+ .setProjection( ProjectionConstants.SCORE, ProjectionConstants.EXPLANATION )
+ .setMaxResults( 1 )
+ .list();
+
+ if ( resultList.size() == 0 ) {
+ score = 0.0f;
+ }
+ else {
+ queryResult = ( Object[] ) resultList.get( 0 );
+ score = ( Float ) queryResult[0];
+ String explanation = queryResult[1].toString();
+ log.debug( "score: " + score + " explanation: " + explanation );
+ }
+ }
+ finally {
+ session.close();
+ }
+ return score;
+ }
+
+ protected Class<?>[] getMappings() {
+ return new Class[] {
+ DynamicBoostedDescriptionLibrary.class
+ };
+ }
+}
Modified: search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/FieldBoostTest.java
===================================================================
--- search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/FieldBoostTest.java 2010-05-11 01:48:17 UTC (rev 19464)
+++ search/branches/v3_1_1_GA_CP/src/test/java/org/hibernate/search/test/query/boost/FieldBoostTest.java 2010-05-11 09:39:54 UTC (rev 19465)
@@ -12,12 +12,14 @@
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.util.LoggerFactory;
+import org.slf4j.Logger;
/**
* @author John Griffin
*/
public class FieldBoostTest extends SearchTestCase {
-
+ private static final Logger log = LoggerFactory.make();
public void testBoostedGetDesc() throws Exception {
FullTextSession fullTextSession = Search.getFullTextSession( openSession() );
buildBoostedGetIndex( fullTextSession );
@@ -33,14 +35,14 @@
BooleanQuery query = new BooleanQuery();
query.add( author, BooleanClause.Occur.SHOULD );
query.add( desc, BooleanClause.Occur.SHOULD );
- //System.out.println( query.toString() );
+ log.debug( query.toString() );
org.hibernate.search.FullTextQuery hibQuery =
fullTextSession.createFullTextQuery( query, BoostedGetDescriptionLibrary.class );
List results = hibQuery.list();
- //System.out.println( hibQuery.explain( 0 ) );
- //System.out.println( hibQuery.explain( 1 ) );
+ log.debug( hibQuery.explain( 0 ).toString() );
+ log.debug( hibQuery.explain( 1 ).toString() );
assertTrue(
"incorrect document returned",
@@ -71,7 +73,7 @@
BooleanQuery query = new BooleanQuery();
query.add( author, BooleanClause.Occur.SHOULD );
query.add( desc, BooleanClause.Occur.SHOULD );
- //System.out.println( query.toString() );
+ log.debug( query.toString() );
org.hibernate.search.FullTextQuery hibQuery =
fullTextSession.createFullTextQuery( query, BoostedFieldDescriptionLibrary.class );
@@ -109,14 +111,14 @@
BooleanQuery query = new BooleanQuery();
query.add( author, BooleanClause.Occur.SHOULD );
query.add( desc, BooleanClause.Occur.SHOULD );
- //System.out.println( query.toString() );
+ log.debug( query.toString() );
org.hibernate.search.FullTextQuery hibQuery =
fullTextSession.createFullTextQuery( query, BoostedDescriptionLibrary.class );
List results = hibQuery.list();
- //System.out.println( hibQuery.explain( 0 ) );
- //System.out.println( hibQuery.explain( 1 ) );
+ log.debug( hibQuery.explain( 0 ).toString() );
+ log.debug( hibQuery.explain( 1 ).toString() );
assertTrue(
"incorrect document returned",
14 years