HHH-6257 : Add IdentifierGenerator to EntityIdentifier binding

This commit is contained in:
Gail Badner 2011-07-20 02:19:37 -07:00
parent edb264ae15
commit f90f224f60
8 changed files with 224 additions and 23 deletions

View File

@ -68,6 +68,16 @@ public class DefaultIdentifierGeneratorFactory implements IdentifierGeneratorFac
private transient Dialect dialect;
private ConcurrentHashMap<String, Class> generatorStrategyToClassNameMap = new ConcurrentHashMap<String, Class>();
/**
* Constructs a new DefaultIdentifierGeneratorFactory
*
* @param dialect The dialect.
*/
public DefaultIdentifierGeneratorFactory(Dialect dialect) {
this();
this.dialect = dialect;
}
/**
* Constructs a new DefaultIdentifierGeneratorFactory.
*/
@ -97,6 +107,10 @@ public class DefaultIdentifierGeneratorFactory implements IdentifierGeneratorFac
}
}
@Override
public Dialect getDialect() {
return dialect;
}
@Override
public void setDialect(Dialect dialect) {

View File

@ -34,6 +34,12 @@ import org.hibernate.type.Type;
* @author Steve Ebersole
*/
public interface IdentifierGeneratorFactory {
/**
* Get the dialect.
*
* @return the dialect
*/
public Dialect getDialect();
/**
* Allow injection of the dialect to use.

View File

@ -178,7 +178,7 @@ public final class SessionFactoryImpl
private final transient Map collectionPersisters;
private final transient Map collectionMetadata;
private final transient Map<String,Set<String>> collectionRolesByEntityParticipant;
private final transient Map identifierGenerators;
private final transient Map<String,IdentifierGenerator> identifierGenerators;
private final transient Map<String, NamedQueryDefinition> namedQueries;
private final transient Map<String, NamedSQLQueryDefinition> namedSqlQueries;
private final transient Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
@ -600,16 +600,13 @@ public final class SessionFactoryImpl
//Generators:
identifierGenerators = new HashMap();
identifierGenerators = new HashMap<String,IdentifierGenerator>();
for ( EntityBinding entityBinding : metadata.getEntityBindings() ) {
if ( entityBinding.isRoot() ) {
// TODO: create the IdentifierGenerator while the metadata is being build, then simply
// use EntityBinding.getIdentifierGenerator() (also remove getIdentifierGeneratorFactory from Mappings)
// TODO: this is broken; throws NullPointerException
//IdentifierGenerator generator = entityBinding.getEntityIdentifier().createIdentifierGenerator(
// metadata.getIdentifierGeneratorFactory()
//);
//identifierGenerators.put( entityBinding.getEntity().getName(), generator );
identifierGenerators.put(
entityBinding.getEntity().getName(),
entityBinding.getEntityIdentifier().getIdentifierGenerator()
);
}
}

View File

@ -84,17 +84,9 @@ public class EntityIdentifier {
return isIdentifierMapper;
}
public IdentifierGenerator createIdentifierGenerator(IdentifierGeneratorFactory factory) {
if ( identifierGenerator == null ) {
Properties props = new Properties();
if ( idGenerator != null ) {
props.putAll( idGenerator.getParameters() );
}
identifierGenerator = factory.createIdentifierGenerator(
idGenerator.getStrategy(),
getValueBinding().getHibernateTypeDescriptor().getResolvedTypeMapping(),
props
);
public IdentifierGenerator createIdentifierGenerator(IdentifierGeneratorFactory factory, Properties properties) {
if ( idGenerator != null ) {
identifierGenerator = attributeBinding.createIdentifierGenerator( idGenerator, factory, properties );
}
return identifierGenerator;
}

View File

@ -63,6 +63,13 @@ public class IdGenerator implements Serializable {
* @return generator configuration parameters
*/
public Map<String, String> getParameters() {
return Collections.unmodifiableMap(parameters);
Map<String, String> returnedParameters;
if ( parameters == null ) {
returnedParameters = Collections.emptyMap();
}
else {
returnedParameters = Collections.unmodifiableMap(parameters);
}
return returnedParameters;
}
}

View File

@ -23,8 +23,17 @@
*/
package org.hibernate.metamodel.binding;
import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.mapping.PropertyGeneration;
import org.hibernate.metamodel.domain.AbstractAttributeContainer;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.source.MetaAttributeContext;
import org.hibernate.metamodel.binding.state.SimpleAttributeBindingState;
import org.hibernate.metamodel.domain.SingularAttribute;
@ -159,4 +168,77 @@ public class SimpleAttributeBinding extends AbstractAttributeBinding implements
public void setMetaAttributeContext(MetaAttributeContext metaAttributeContext) {
this.metaAttributeContext = metaAttributeContext;
}
/* package-protected */
IdentifierGenerator createIdentifierGenerator(
IdGenerator idGenerator,
IdentifierGeneratorFactory identifierGeneratorFactory,
Properties properties) {
Properties params = new Properties();
params.putAll( properties );
// use the schema/catalog specified by getValue().getTable() - but note that
// if the schema/catalog were specified as params, they will already be initialized and
//will override the values set here (they are in idGenerator.getParameters().)
Schema schema = getValue().getTable().getSchema();
if ( schema != null ) {
if ( schema.getName().getSchema() != null ) {
params.setProperty( PersistentIdentifierGenerator.SCHEMA, schema.getName().getSchema().getName() );
}
if ( schema.getName().getCatalog() != null ) {
params.setProperty(PersistentIdentifierGenerator.CATALOG, schema.getName().getCatalog().getName() );
}
}
// TODO: not sure how this works for collection IDs...
//pass the entity-name, if not a collection-id
//if ( rootClass!=null) {
params.setProperty( IdentifierGenerator.ENTITY_NAME, getEntityBinding().getEntity().getName() );
//}
//init the table here instead of earlier, so that we can get a quoted table name
//TODO: would it be better to simply pass the qualified table name, instead of
// splitting it up into schema/catalog/table names
String tableName = getValue().getTable().getQualifiedName( identifierGeneratorFactory.getDialect() );
params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
//pass the column name (a generated id almost always has a single column)
if ( getValuesSpan() != 1 ) {
throw new MappingException( "A SimpleAttributeBinding has a more than 1 Value: " + getAttribute().getName() );
}
SimpleValue simpleValue = getValues().iterator().next();
if ( ! Column.class.isInstance( simpleValue ) ) {
throw new MappingException(
"Cannot create an IdentifierGenerator because the value is not a column: " +
simpleValue.toLoggableString()
);
}
params.setProperty(
PersistentIdentifierGenerator.PK,
( ( Column ) simpleValue ).getColumnName().encloseInQuotesIfQuoted(
identifierGeneratorFactory.getDialect()
)
);
// TODO: is this stuff necessary for SimpleValue???
//if (rootClass!=null) {
// StringBuffer tables = new StringBuffer();
// Iterator iter = rootClass.getIdentityTables().iterator();
// while ( iter.hasNext() ) {
// Table table= (Table) iter.next();
// tables.append( table.getQuotedName(dialect) );
// if ( iter.hasNext() ) tables.append(", ");
// }
// params.setProperty( PersistentIdentifierGenerator.TABLES, tables.toString() );
//}
//else {
params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
//}
params.putAll( idGenerator.getParameters() );
return identifierGeneratorFactory.createIdentifierGenerator(
idGenerator.getStrategy(), getHibernateTypeDescriptor().getResolvedTypeMapping(), params
);
}
}

View File

@ -0,0 +1,97 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.internal;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.config.spi.ConfigurationService;
/**
* @author Gail Badner
*/
public class IdentifierGeneratorResolver {
private final MetadataImplementor metadata;
IdentifierGeneratorResolver(MetadataImplementor metadata) {
this.metadata = metadata;
}
// IdentifierGeneratorResolver.resolve() must execute after AttributeTypeResolver.resolve()
// to ensure that identifier type is resolved.
@SuppressWarnings( {"unchecked"} )
void resolve() {
for ( EntityBinding entityBinding : metadata.getEntityBindings() ) {
if ( entityBinding.isRoot() ) {
Properties properties = new Properties( );
properties.putAll(
metadata.getServiceRegistry()
.getService( ConfigurationService.class )
.getSettings()
);
//TODO: where should these be added???
if ( ! properties.contains( AvailableSettings.PREFER_POOLED_VALUES_LO ) ) {
properties.put( AvailableSettings.PREFER_POOLED_VALUES_LO, "false" );
}
if ( ! properties.contains( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER ) ) {
properties.put(
PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
new ObjectNameNormalizerImpl( metadata )
);
}
entityBinding.getEntityIdentifier().createIdentifierGenerator(
metadata.getIdentifierGeneratorFactory(),
properties
);
}
}
}
private static class ObjectNameNormalizerImpl extends ObjectNameNormalizer implements Serializable {
private final boolean useQuotedIdentifiersGlobally;
private final NamingStrategy namingStrategy;
private ObjectNameNormalizerImpl(MetadataImplementor metadata ) {
this.useQuotedIdentifiersGlobally = metadata.isGloballyQuotedIdentifiers();
this.namingStrategy = metadata.getNamingStrategy();
}
@Override
protected boolean isUseQuotedIdentifiersGlobally() {
return useQuotedIdentifiersGlobally;
}
@Override
protected NamingStrategy getNamingStrategy() {
return namingStrategy;
}
}
}

View File

@ -38,7 +38,9 @@ import org.hibernate.SessionFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
@ -93,7 +95,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private SessionFactoryBuilder sessionFactoryBuilder = new SessionFactoryBuilderImpl( this );
private DefaultIdentifierGeneratorFactory identifierGeneratorFactory = new DefaultIdentifierGeneratorFactory();
private final DefaultIdentifierGeneratorFactory identifierGeneratorFactory;
private final Database database;
@ -117,8 +119,10 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private boolean globallyQuotedIdentifiers = false;
public MetadataImpl(MetadataSources metadataSources, Options options) {
Dialect dialect = metadataSources.getServiceRegistry().getService( JdbcServices.class ).getDialect();
this.serviceRegistry = metadataSources.getServiceRegistry();
this.options = options;
this.identifierGeneratorFactory = new DefaultIdentifierGeneratorFactory( dialect );
this.database = new Database( options );
this.mappingDefaults = new MappingDefaultsImpl();
@ -166,6 +170,8 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
// todo : remove this by coordinated ordering of entity processing
new EntityReferenceResolver( this ).resolve();
new AttributeTypeResolver( this ).resolve();
// IdentifierGeneratorResolver.resolve() must execute after AttributeTypeResolver.resolve()
new IdentifierGeneratorResolver( this ).resolve();
}
private void prepare(MetadataSourceProcessor[] metadataSourceProcessors, MetadataSources metadataSources) {