HHH-8897 : Integrate org.hibernate.metamodel from metamodel branch into master

This commit is contained in:
Gail Badner 2014-01-27 05:47:54 -08:00
parent 1a87adca08
commit 513f8ca869
1082 changed files with 69831 additions and 22634 deletions

View File

@ -137,6 +137,7 @@ subprojects { subProject ->
dependencies {
compile( libraries.logging )
compile( libraries.logging_annotations )
compile( libraries.logging_processor )
testCompile( libraries.junit )
testCompile( libraries.byteman )
@ -152,8 +153,11 @@ subprojects { subProject ->
jaxb( libraries.jaxb ){
exclude group: "javax.xml.stream"
}
jaxb( libraries.jaxb )
jaxb( libraries.jaxb2_basics )
jaxb( libraries.jaxb2_ant )
jaxb( libraries.jaxb2_jaxb )
jaxb( libraries.jaxb2_jaxb_xjc )
animalSniffer ( libraries.animal_sniffer )
javaApiSignature ( libraries.java16_signature )

View File

@ -10,6 +10,7 @@ versionInjection {
dependencies {
compile( libraries.jta )
compile( libraries.dom4j )
compile( libraries.classmate )
compile( libraries.commons_annotations )
compile( libraries.jpa )
compile( libraries.javassist )
@ -21,7 +22,6 @@ dependencies {
provided( libraries.ant )
provided( libraries.jacc )
provided( libraries.validation )
provided( libraries.classmate )
testCompile( project(':hibernate-testing') )
testCompile( libraries.validation )
@ -111,7 +111,7 @@ task jaxb {
// input schemas
cfgXsd = file( 'src/main/resources/org/hibernate/hibernate-configuration-4.0.xsd')
hbmXsd = file( 'src/main/resources/org/hibernate/hibernate-mapping-4.0.xsd' )
ormXsd = file( 'src/main/resources/org/hibernate/jpa/orm_2_0.xsd' )
ormXsd = file( 'src/main/resources/org/hibernate/jpa/orm_2_1.xsd' )
// input bindings
cfgXjb = file( 'src/main/xjb/hbm-configuration-bindings.xjb' )
@ -133,7 +133,7 @@ task jaxb {
// hibernate-configuration
ant.xjc(
destdir: '${jaxbTargetDir}',
package: 'org.hibernate.internal.jaxb.cfg',
package: 'org.hibernate.jaxb.spi.cfg',
binding: 'src/main/xjb/hbm-configuration-bindings.xjb',
schema: cfgXsd.path
)
@ -141,21 +141,25 @@ task jaxb {
// hibernate-mapping
ant.xjc(
destdir: '${jaxbTargetDir}',
package: 'org.hibernate.internal.jaxb.mapping.hbm',
package: 'org.hibernate.jaxb.spi.hbm',
binding: hbmXjb.path,
schema: hbmXsd.path,
extension: 'true'
) {
arg line: '-Xinheritance'
arg line: '-Xinheritance -Xsimplify'
}
// orm.xml (jpa)
ant.xjc(
destdir: '${jaxbTargetDir}',
package: 'org.hibernate.internal.jaxb.mapping.orm',
package: 'org.hibernate.jaxb.spi.orm',
binding: 'src/main/xjb/orm-bindings.xjb',
schema: ormXsd.path
)
schema: ormXsd.path,
extension: 'true'
) {
arg line: '-Xinheritance'
}
}
}

View File

@ -23,7 +23,7 @@
*/
package org.hibernate;
import org.hibernate.internal.jaxb.Origin;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.internal.util.xml.XmlDocument;
/**

View File

@ -30,6 +30,8 @@ import java.util.Set;
import javax.naming.Referenceable;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.cfg.Settings;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
@ -71,6 +73,12 @@ public interface SessionFactory extends Referenceable, Serializable {
*/
public Interceptor getInterceptor();
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
public SessionFactoryObserver[] getSessionFactoryObservers();
public EntityNameResolver[] getEntityNameResolvers();
public Settings getSettings();
/**
* Get the delegate for handling entity-not-found exception conditions.
*

View File

@ -0,0 +1,48 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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;
/**
* An enumeration of truth values.
* <p/>
* Yes this *could* be handled with Boolean, but then you run into potential problems with premature
* auto-unboxing.
*
* @author Steve Ebersole
*/
public enum TruthValue {
TRUE,
FALSE,
UNKNOWN;
public static boolean toBoolean(TruthValue value, boolean defaultValue) {
if ( value == TruthValue.TRUE ) {
return true;
}
if ( value == TruthValue.FALSE ) {
return false;
}
return defaultValue;
}
}

View File

@ -0,0 +1,54 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.annotations;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation used to indicate that an entity represents shared (non tenant aware) data in a multi-tenant
* application.
*
* Valid only at the root of an inheritance hierarchy.
*
* @author Steve Ebersole
*/
@java.lang.annotation.Target(TYPE)
@Retention(RUNTIME)
public @interface MultiTenancy {
public boolean shared() default true;
/**
* The discriminator values can be either be handled as literals or handled through JDBC parameter binding.
* {@code true} here (the default) indicates that the parameter binding approach should be used; {@code false}
* indicates the value should be handled as a literal.
* <p/>
* Care should be used specifying to use literals here. PreparedStatements will not be able to be reused
* nearly as often by the database/driver which can potentially cause a significant performance impact to your
* application.
*/
public boolean useParameterBinding() default true;
}

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.annotations;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Describes the column to use as the multi-tenancy discriminator value for the entity.
*
* @author Steve Ebersole
*/
@java.lang.annotation.Target( TYPE )
@Retention( RUNTIME )
public @interface TenantColumn {
/**
* Name of the column to use.
*/
public String name();
/**
* (Optional) The name of the table that contains the column. If absent the column is assumed to be in the
* primary table.
*/
public String table() default "";
/**
* Names the Hibernate mapping type to use for mapping values to/from the specified column. Defaults to
* {@code "string"} which is a {@link String}/{@link java.sql.Types#VARCHAR VARCHAR} mapping.
*/
public String type() default "string";
/**
* (Optional) The column length. (Applies only if a string-valued column is used.)
*/
int length() default 255;
/**
* (Optional) The precision for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
* Value must be set by developer if used when generating the DDL for the column.
*/
int precision() default 0;
/**
* (Optional) The scale for a decimal (exact numeric) column. (Applies only if a decimal column is used.)
*/
int scale() default 0;
}

View File

@ -0,0 +1,44 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.annotations;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Describes a formula fragment to use as the multi-tenancy discriminator value for the entity.
*
* @author Steve Ebersole
* @see Formula
*/
@java.lang.annotation.Target(TYPE)
@Retention(RUNTIME)
public @interface TenantFormula {
/**
* The formula fragment.
*/
public String value();
}

View File

@ -34,7 +34,7 @@ import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.cfg.Environment;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.internal.jaxb.cfg.JaxbHibernateConfiguration;
import org.hibernate.jaxb.spi.cfg.JaxbHibernateConfiguration;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.ConfigLoader;
import org.hibernate.service.Service;

View File

@ -140,7 +140,8 @@ public class StrategySelectorBuilder {
throw new StrategySelectionException(
"Implementation class [" + strategyRegistration.getStrategyImplementation().getName()
+ "] does not implement strategy interface ["
+ strategyRegistration.getStrategyRole().getName() + "]"
+ strategyRegistration.getStrategyRole().getName() + "]",
strategyRegistration.getStrategyImplementation().getName()
);
}
explicitStrategyRegistrations.add( strategyRegistration );

View File

@ -126,7 +126,8 @@ public class StrategySelectorImpl implements StrategySelector {
}
catch (ClassLoadingException e) {
throw new StrategySelectionException(
"Unable to resolve name [" + name + "] as strategy [" + strategy.getName() + "]"
"Unable to resolve name [" + name + "] as strategy [" + strategy.getName() + "]",
name
);
}
}
@ -161,7 +162,8 @@ public class StrategySelectorImpl implements StrategySelector {
catch (Exception e) {
throw new StrategySelectionException(
String.format( "Could not instantiate named strategy class [%s]", implementationClass.getName() ),
e
e,
implementationClass.getName()
);
}
}

View File

@ -31,13 +31,16 @@ import org.hibernate.HibernateException;
* @author Steve Ebersole
*/
public class StrategySelectionException extends HibernateException {
private final String implementationClassName;
/**
* Constructs a StrategySelectionException using the specified message.
*
* @param message A message explaining the exception condition.
*/
public StrategySelectionException(String message) {
public StrategySelectionException(String message, String implementationClassName) {
super( message );
this.implementationClassName = implementationClassName;
}
/**
@ -46,7 +49,17 @@ public class StrategySelectionException extends HibernateException {
* @param message A message explaining the exception condition.
* @param cause The underlying cause.
*/
public StrategySelectionException(String message, Throwable cause) {
public StrategySelectionException(String message, Throwable cause, String implementationClassName) {
super( message, cause );
this.implementationClassName = implementationClassName;
}
/**
* Gets the selected implementation class involved with the exception.
*
* @return the implementation class name.
*/
public String getImplementationClassName() {
return implementationClassName;
}
}

View File

@ -0,0 +1,81 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.boot.spi;
/**
* Models the definition of caching settings for a particular region. Generally as found in either:<ul>
* <li>{@code cfg.xml}</li>
* <li>{@code hbm.xml}</li>
* <li>annotation</li>
* </ul>
* Though certainly other custom sources are acceptable too.
*
* @author Steve Ebersole
*/
public class CacheRegionDefinition {
public static enum CacheRegionType {
ENTITY,
COLLECTION,
QUERY
}
private final CacheRegionType regionType;
private final String role;
private final String usage;
private final String region;
private final boolean cacheLazy;
public CacheRegionDefinition(
CacheRegionType cacheType,
String role,
String usage,
String region,
boolean cacheLazy) {
this.regionType = cacheType;
this.role = role;
this.usage = usage;
this.region = region;
this.cacheLazy = cacheLazy;
}
public CacheRegionType getRegionType() {
return regionType;
}
public String getRole() {
return role;
}
public String getUsage() {
return usage;
}
public String getRegion() {
return region;
}
public boolean isCacheLazy() {
return cacheLazy;
}
}

View File

@ -28,8 +28,8 @@ import java.util.Comparator;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.type.VersionType;
/**
@ -134,7 +134,7 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
private static Comparator getVersionComparator(EntityBinding model ) {
if ( model.isVersioned() ) {
final VersionType versionType = (VersionType) model.getHierarchyDetails()
.getVersioningAttributeBinding()
.getEntityVersion().getVersioningAttributeBinding()
.getHibernateTypeDescriptor()
.getResolvedTypeMapping();

View File

@ -39,7 +39,7 @@ import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

View File

@ -636,7 +636,51 @@ public interface AvailableSettings {
*/
String IGNORE_EXPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS = "hibernate.discriminator.ignore_explicit_for_joined";
String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
/**
* Names a {@link org.hibernate.Interceptor} implementation to be applied to the {@link org.hibernate.SessionFactory}
* Can reference<ul>
* <li>Interceptor instance</li>
* <li>Interceptor implementation {@link Class} reference</li>
* <li>Interceptor implementation class name</li>
* </ul>
*
* @since 5.0
*/
String INTERCEPTOR = "hibernate.sessionFactory.interceptor";
/**
* Setting that controls whether we seek out JPA "static metamodel" classes and populate them. Accepts
* 3 values:<ul>
* <li>
* <b>enabled</b> - Do the population
* </li>
* <li>
* <b>disabled</b> - Do not do the population
* </li>
* <li>
* <b>ignoreUnsupported</b> - Do the population, but ignore any non-JPA features that would otherwise
* result in the population failing.
* </li>
* </ul>
*/
public static final String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population";
/**
* Used to specify the {@link org.hibernate.tool.schema.spi.SchemaManagementTool} to use for performing
* schema management. The default is to use {@link org.hibernate.tool.schema.internal.HibernateSchemaManagementTool}
*
* @since 5.0
*/
String SCHEMA_MANAGEMENT_TOOL = "hibernate.schema_management_tool";
/**
* A constant naming the setting used to identify the {@link org.hibernate.engine.jdbc.spi.SchemaNameResolver} to use
* <p/>
* TODO : add to Environment
*/
String SCHEMA_NAME_RESOLVER = "hibernate.schema_name_resolver";
String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy";
@ -701,6 +745,15 @@ public interface AvailableSettings {
*/
String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy";
/**
* If enabled, an entity's member field types and method return types will automatically be indexed. This allows,
* for example, auto-discovery of @Embeddables without explicitly listing them in the annotated classes. This
* setting will also check classes identified by certain annotations (such as @Target). JPA requires these classes
* to be identified in the annotated classes, however legacy Hibernate behavior was to allow it. Due to the
* performance hit, disabled by default.
*/
String ENABLE_AUTO_INDEX_MEMBER_TYPES = "hibernate.enable_auto_index_member_types";
/**
* A setting to control whether to {@link org.hibernate.engine.internal.StatisticalLoggingSessionEventListener} is
* enabled on all Sessions (unless explicitly disabled for a given Session). The default value of this

View File

@ -24,9 +24,12 @@
package org.hibernate.cfg;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/**
* The default <tt>NamingStrategy</tt>
@ -93,6 +96,22 @@ public class DefaultNamingStrategy implements NamingStrategy, Serializable {
if (header == null) throw new AssertionFailure("NammingStrategy not properly filled");
return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
}
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
/**
* Return the column name or the unqualified property name

View File

@ -23,9 +23,12 @@
*/
package org.hibernate.cfg;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/**
* Naming strategy implementing the EJB3 standards
@ -76,6 +79,22 @@ public class EJB3NamingStrategy implements NamingStrategy, Serializable {
if ( header == null ) throw new AssertionFailure( "NamingStrategy not properly filled" );
return columnName( header + "_" + referencedColumnName );
}
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
public String logicalColumnName(String columnName, String propertyName) {
return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName );

View File

@ -1724,8 +1724,8 @@ public final class HbmBinder {
oneToOne.setConstrained( constrained );
oneToOne.setForeignKeyType( constrained ?
ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT :
ForeignKeyDirection.FOREIGN_KEY_TO_PARENT );
ForeignKeyDirection.FROM_PARENT :
ForeignKeyDirection.TO_PARENT );
initOuterJoinFetchSetting( node, oneToOne );
initLaziness( node, oneToOne, mappings, true );

View File

@ -24,9 +24,12 @@
package org.hibernate.cfg;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/**
* An improved naming strategy that prefers embedded
@ -106,6 +109,22 @@ public class ImprovedNamingStrategy implements NamingStrategy, Serializable {
if (header == null) throw new AssertionFailure("NamingStrategy not properly filled");
return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
}
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
/**
* Return the column name or the unqualified property name

View File

@ -23,6 +23,8 @@
*/
package org.hibernate.cfg;
import java.util.List;
/**
* A set of rules for determining the physical column
@ -37,6 +39,7 @@ package org.hibernate.cfg;
* @see ImprovedNamingStrategy
* @author Gavin King
* @author Emmanuel Bernard
* @author Brett Meyer
*/
public interface NamingStrategy {
/**
@ -93,6 +96,33 @@ public interface NamingStrategy {
public String foreignKeyColumnName(
String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName
);
/**
* Return a constraint name for foreign keys that are not explicitly named in the mappings/annotations.
*
* @param tableName The foreign key's source table
* @param columnNames The source columns within the foreign key
* @param tableName The foreign key's target table
* @param columnNames The target columns within the foreign key
* @return The generated foreign key constraint name
*/
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames);
/**
* Return a constraint name for unique keys that are not explicitly named in the mappings/annotations.
*
* @param tableName The unique key's table
* @param columnNames The columns within the unique key
* @return The generated unique key constraint name
*/
public String uniqueKeyName(String tableName, List<String> columnNames);
/**
* Return a constraint name for indexes that are not explicitly named in the mappings/annotations.
*
* @param tableName The index's table
* @param columnNames The columns within the index
* @return The generated index constraint name
*/
public String indexName(String tableName, List<String> columnNames);
/**
* Return the logical column name used to refer to a column in the metadata
* (like index, unique constraints etc)

View File

@ -56,6 +56,10 @@ public abstract class ObjectNameNormalizer {
public String handleExplicitName(NamingStrategy strategy, String name);
}
public static interface LogicalNamingStrategyHelper extends NamingStrategyHelper{
public String getLogicalName(NamingStrategy strategy);
}
/**
* Performs the actual contract of normalizing a database name.
*
@ -78,7 +82,6 @@ public abstract class ObjectNameNormalizer {
// handle any quoting for consistent handling in naming strategies
objectName = normalizeIdentifierQuoting( explicitName );
objectName = helper.handleExplicitName( getNamingStrategy(), objectName );
return normalizeIdentifierQuoting( objectName );
}
// Conceivable that the naming strategy could return a quoted identifier, or
// that user enabled <delimited-identifiers/>

View File

@ -106,8 +106,8 @@ public class OneToOneSecondPass implements SecondPass {
if ( !optional ) value.setConstrained( true );
value.setForeignKeyType(
value.isConstrained() ?
ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT :
ForeignKeyDirection.FOREIGN_KEY_TO_PARENT
ForeignKeyDirection.FROM_PARENT :
ForeignKeyDirection.TO_PARENT
);
PropertyBinder binder = new PropertyBinder();
binder.setName( propertyName );

View File

@ -42,7 +42,7 @@ import org.hibernate.cache.spi.QueryCacheFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.engine.transaction.spi.TransactionFactory;

View File

@ -33,7 +33,7 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jboss.logging.Logger;

View File

@ -80,6 +80,11 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.io.StreamCopier;
import org.hibernate.mapping.Column;
import org.hibernate.metamodel.spi.TypeContributions;
import org.hibernate.metamodel.spi.relational.AuxiliaryDatabaseObject;
import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.Index;
import org.hibernate.metamodel.spi.relational.Sequence;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
@ -89,6 +94,13 @@ import org.hibernate.sql.ANSIJoinFragment;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.sql.JoinFragment;
import org.hibernate.tool.schema.internal.StandardAuxiliaryDatabaseObjectExporter;
import org.hibernate.tool.schema.internal.StandardForeignKeyExporter;
import org.hibernate.tool.schema.internal.StandardIndexExporter;
import org.hibernate.tool.schema.internal.StandardSequenceExporter;
import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.internal.TemporaryTableExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -1965,6 +1977,37 @@ public abstract class Dialect implements ConversionContext {
// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private StandardTableExporter tableExporter = new StandardTableExporter( this );
private StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this );
private StandardIndexExporter indexExporter = new StandardIndexExporter( this );
private StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this );
private StandardAuxiliaryDatabaseObjectExporter auxiliaryObjectExporter = new StandardAuxiliaryDatabaseObjectExporter( this );
private TemporaryTableExporter temporaryTableExporter = new TemporaryTableExporter( this );
public Exporter<Table> getTableExporter() {
return tableExporter;
}
public Exporter<Table> getTemporaryTableExporter() {
return temporaryTableExporter;
}
public Exporter<Sequence> getSequenceExporter() {
return sequenceExporter;
}
public Exporter<Index> getIndexExporter() {
return indexExporter;
}
public Exporter<ForeignKey> getForeignKeyExporter() {
return foreignKeyExporter;
}
public Exporter<AuxiliaryDatabaseObject> getAuxiliaryDatabaseObjectExporter() {
return auxiliaryObjectExporter;
}
/**
* Get the SQL command used to create the named schema
*
@ -1987,6 +2030,15 @@ public abstract class Dialect implements ConversionContext {
return "drop schema " + schemaName;
}
/**
* Get the SQL command used to retrieve the current schema name
*
* @return The current schema retrieval SQL
*/
public String getCurrentSchemaCommand() {
return null;
}
/**
* Does this dialect support the <tt>ALTER TABLE</tt> syntax?
*

View File

@ -427,4 +427,9 @@ public class H2Dialect extends Dialect {
public boolean supportsTuplesInSubqueries() {
return false;
}
@Override
public String getCurrentSchemaCommand() {
return "call schema()";
}
}

View File

@ -620,4 +620,9 @@ public class Oracle8iDialect extends Dialect {
// Oracle supports returning cursors
return StandardCallableStatementSupport.REF_CURSOR_INSTANCE;
}
@Override
public String getCurrentSchemaCommand() {
return "select sys_context( 'userenv', 'current_schema' ) from dual";
}
}

View File

@ -23,9 +23,9 @@ package org.hibernate.dialect.unique;
import java.util.Iterator;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Index;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.UniqueKey;
/**
* DB2 does not allow unique constraints on nullable columns. Rather than
@ -68,13 +68,27 @@ public class DB2UniqueDelegate extends DefaultUniqueDelegate {
@Override
public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey) {
if ( hasNullable( uniqueKey ) ) {
return Index.buildSqlCreateIndexString(
dialect,
uniqueKey.getName(),
uniqueKey.getTable(),
uniqueKey.getColumns(),
true
);
// TODO: This borrows from Index's old way of doing things. This
// should be using StandardIndexExporter. However, not all callers
// have JdbcEnvironment available. We'll need to refactor a bit...
String keyName = dialect.qualifyIndexName() ? uniqueKey.getName()
: StringHelper.unqualify( uniqueKey.getName() );
StringBuilder buf = new StringBuilder( "create unique index " )
.append( keyName ).append( " on " )
.append( uniqueKey.getTable().getQualifiedName( dialect ) )
.append( " (" );
boolean first = true;
for ( Column column : uniqueKey.getColumns() ) {
if ( first ) {
first = false;
}
else {
buf.append( ", " );
}
buf.append( ( column.getColumnName().getText( dialect ) ) );
}
buf.append( ")" );
return buf.toString();
}
else {
return super.getAlterTableToAddUniqueKeyCommand( uniqueKey );
@ -105,7 +119,12 @@ public class DB2UniqueDelegate extends DefaultUniqueDelegate {
@Override
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey) {
if ( hasNullable( uniqueKey ) ) {
return Index.buildSqlDropIndexString( dialect, uniqueKey.getTable(), uniqueKey.getName() );
// TODO: This borrows from Index's old way of doing things. This
// should be using StandardIndexExporter. However, not all callers
// have JdbcEnvironment available. We'll need to refactor a bit...
return "drop index " + StringHelper.qualify(
uniqueKey.getTable().getQualifiedName( dialect ),
uniqueKey.getName() );
}
else {
return super.getAlterTableToDropUniqueKeyCommand( uniqueKey );

View File

@ -23,9 +23,9 @@ package org.hibernate.dialect.unique;
import java.util.Iterator;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.UniqueKey;
/**
* The default UniqueDelegate implementation for most dialects. Uses
@ -135,8 +135,8 @@ public class DefaultUniqueDelegate implements UniqueDelegate {
final StringBuilder sb = new StringBuilder( " unique (" );
final Iterator columnIterator = uniqueKey.getColumns().iterator();
while ( columnIterator.hasNext() ) {
final org.hibernate.mapping.Column column = (org.hibernate.mapping.Column) columnIterator.next();
sb.append( column.getQuotedName( dialect ) );
Column column = (Column) columnIterator.next();
sb.append( column.getColumnName().getText( dialect ) );
if ( columnIterator.hasNext() ) {
sb.append( ", " );
}
@ -149,10 +149,17 @@ public class DefaultUniqueDelegate implements UniqueDelegate {
public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey) {
// Do this here, rather than allowing UniqueKey/Constraint to do it.
// We need full, simplified control over whether or not it happens.
final String tableName = uniqueKey.getTable().getQualifiedName( dialect );
final String constraintName = dialect.quote( uniqueKey.getName() );
return "alter table " + tableName + " drop constraint " + constraintName;
final StringBuilder buf = new StringBuilder( "alter table " );
buf.append( uniqueKey.getTable().getQualifiedName( dialect ) );
buf.append(" drop constraint " );
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
buf.append( "if exists " );
}
buf.append( dialect.quote( uniqueKey.getName() ) );
if ( dialect.supportsIfExistsAfterConstraintName() ) {
buf.append( " if exists" );
}
return buf.toString();
}

View File

@ -21,7 +21,7 @@
package org.hibernate.dialect.unique;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.spi.relational.UniqueKey;
/**
* Informix requires the constraint name to come last on the alter table.

View File

@ -20,9 +20,9 @@
*/
package org.hibernate.dialect.unique;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.relational.UniqueKey;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.UniqueKey;
/**
* Dialect-level delegate in charge of applying "uniqueness" to a column. Uniqueness can be defined

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.config.spi;
import static org.hibernate.engine.config.spi.ConfigurationService.Converter;
/**
* Standard set of setting converters
*
* @author Steve Ebersole
*/
public class StandardConverters {
public static final Converter<Boolean> BOOLEAN = new Converter<Boolean>() {
@Override
public Boolean convert(Object value) {
if ( value == null ) {
throw new IllegalArgumentException( "Null value passed to convert" );
}
return Boolean.class.isInstance( value )
? Boolean.class.cast( value )
: Boolean.parseBoolean( value.toString() );
}
};
public static final Converter<String> STRING = new Converter<String>() {
@Override
public String convert(Object value) {
if ( value == null ) {
throw new IllegalArgumentException( "Null value passed to convert" );
}
return value.toString();
}
};
/**
* Disallow direct instantiation
*/
private StandardConverters() {
}
}

View File

@ -222,7 +222,7 @@ public final class Cascade {
}
if (type.isAssociationType() && ((AssociationType)type).getForeignKeyDirection().equals(
ForeignKeyDirection.FOREIGN_KEY_TO_PARENT )) {
ForeignKeyDirection.TO_PARENT )) {
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
// occur. Otherwise, replacing the association on a managed entity, without manually
// nulling and flushing, causes FK constraint violations.

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.connections.internal;
import org.hibernate.HibernateException;
/**
* @author Steve Ebersole
*/
public class UserSuppliedConnectionException extends HibernateException {
public UserSuppliedConnectionException() {
super( "The application must supply JDBC connections" );
}
}

View File

@ -58,12 +58,12 @@ public class UserSuppliedConnectionProviderImpl implements ConnectionProvider {
@Override
public Connection getConnection() throws SQLException {
throw new UnsupportedOperationException( "The application must supply JDBC connections" );
throw new UserSuppliedConnectionException();
}
@Override
public void closeConnection(Connection conn) throws SQLException {
throw new UnsupportedOperationException( "The application must supply JDBC connections" );
throw new UserSuppliedConnectionException();
}
@Override

View File

@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.connections.spi;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Provides centralized access to JDBC connections. Centralized to hide the complexity of accounting for contextual
* (multi-tenant) versus non-contextual access.
*
* @author Steve Ebersole
*/
public interface JdbcConnectionAccess extends Serializable {
/**
* Obtain a JDBC connection
*
* @return The obtained connection
*
* @throws SQLException Indicates a problem getting the connection
*/
public Connection obtainConnection() throws SQLException;
/**
* Release a previously obtained connection
*
* @param connection The connection to release
*
* @throws SQLException Indicates a problem releasing the connection
*/
public void releaseConnection(Connection connection) throws SQLException;
/**
* Does the underlying provider of connections support aggressive releasing of connections (and re-acquisition
* of those connections later, if need be) in JTA environments?
*
* @see org.hibernate.engine.jdbc.connections.spi.ConnectionProvider#supportsAggressiveRelease()
* @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#supportsAggressiveRelease()
*/
public boolean supportsAggressiveRelease();
}

View File

@ -0,0 +1,69 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.internal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
/**
* Default implementation
*
* @author Steve Ebersole
*/
public class DefaultSchemaNameResolver implements SchemaNameResolver {
public static final DefaultSchemaNameResolver INSTANCE = new DefaultSchemaNameResolver();
@Override
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException {
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery( dialect.getCurrentSchemaCommand() );
try {
if ( ! resultSet.next() ) {
return null;
}
return resultSet.getString( 1 );
}
finally {
try {
resultSet.close();
}
catch (SQLException ignore) {
}
}
}
finally {
try {
statement.close();
}
catch (SQLException ignore) {
}
}
}
}

View File

@ -0,0 +1,142 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.internal;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.env.spi.SQLStateType;
/**
* Standard implementation of ExtractedDatabaseMetaData
*
* @author Steve Ebersole
*/
public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData {
private final JdbcEnvironment jdbcEnvironment;
private final boolean supportsRefCursors;
private final boolean supportsNamedParameters;
private final boolean supportsScrollableResults;
private final boolean supportsGetGeneratedKeys;
private final boolean supportsBatchUpdates;
private final boolean supportsDataDefinitionInTransaction;
private final boolean doesDataDefinitionCauseTransactionCommit;
private final SQLStateType sqlStateType;
private final boolean lobLocatorUpdateCopy;
/**
* Form used when {@link java.sql.DatabaseMetaData} is not available.
*
* @param jdbcEnvironment The JDBC environment containing this metadata.
*/
public ExtractedDatabaseMetaDataImpl(JdbcEnvironment jdbcEnvironment) {
this.jdbcEnvironment = jdbcEnvironment;
// if possible, set values that will allow things to still work....
this.supportsRefCursors = false; // Java 8 feature, safest to say not.
this.supportsNamedParameters = false;
this.supportsScrollableResults = false;
this.supportsGetGeneratedKeys = false;
this.supportsBatchUpdates = false;
this.sqlStateType = SQLStateType.UNKNOWN;
this.lobLocatorUpdateCopy = false;
// ugh my favorites...
this.supportsDataDefinitionInTransaction = true;
this.doesDataDefinitionCauseTransactionCommit = false;
}
public ExtractedDatabaseMetaDataImpl(
JdbcEnvironmentImpl jdbcEnvironment,
boolean supportsRefCursors,
boolean supportsNamedParameters,
boolean supportsScrollableResults,
boolean supportsGetGeneratedKeys,
boolean supportsBatchUpdates,
boolean supportsDataDefinitionInTransaction,
boolean doesDataDefinitionCauseTransactionCommit,
SQLStateType sqlStateType,
boolean lobLocatorUpdateCopy) {
this.jdbcEnvironment = jdbcEnvironment;
this.supportsRefCursors = supportsRefCursors;
this.supportsNamedParameters = supportsNamedParameters;
this.supportsScrollableResults = supportsScrollableResults;
this.supportsGetGeneratedKeys = supportsGetGeneratedKeys;
this.supportsBatchUpdates = supportsBatchUpdates;
this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction;
this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit;
this.sqlStateType = sqlStateType;
this.lobLocatorUpdateCopy = lobLocatorUpdateCopy;
}
@Override
public boolean supportsRefCursors() {
return supportsRefCursors;
}
@Override
public JdbcEnvironment getJdbcEnvironment() {
return jdbcEnvironment;
}
@Override
public boolean supportsNamedParameters() {
return supportsNamedParameters;
}
@Override
public boolean supportsScrollableResults() {
return supportsScrollableResults;
}
@Override
public boolean supportsGetGeneratedKeys() {
return supportsGetGeneratedKeys;
}
@Override
public boolean supportsBatchUpdates() {
return supportsBatchUpdates;
}
@Override
public boolean supportsDataDefinitionInTransaction() {
return supportsDataDefinitionInTransaction;
}
@Override
public boolean doesDataDefinitionCauseTransactionCommit() {
return doesDataDefinitionCauseTransactionCommit;
}
@Override
public SQLStateType getSqlStateType() {
return sqlStateType;
}
@Override
public boolean doesLobLocatorUpdateCopy() {
return lobLocatorUpdateCopy;
}
}

View File

@ -0,0 +1,339 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.internal;
import java.lang.reflect.InvocationTargetException;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.hibernate.boot.registry.selector.spi.StrategySelectionException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder;
import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameSupport;
import org.hibernate.engine.jdbc.env.spi.SQLStateType;
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.env.spi.StandardQualifiedObjectNameSupportImpl;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* @author Steve Ebersole
*/
public class JdbcEnvironmentImpl implements JdbcEnvironment {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcEnvironmentImpl.class );
private final ServiceRegistryImplementor serviceRegistry;
private final Dialect dialect;
private final SqlExceptionHelper sqlExceptionHelper;
private final ExtractedDatabaseMetaData extractedMetaDataSupport;
private final Set<String> reservedWords;
private final Identifier currentCatalog;
private final Identifier currentSchema;
private final IdentifierHelper identifierHelper;
private final QualifiedObjectNameSupport qualifiedObjectNameSupport;
private final LobCreatorBuilderImpl lobCreatorBuilder;
private final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
/**
* Constructor form used when the JDBC {@link DatabaseMetaData} is not available.
*
* @param serviceRegistry The service registry
* @param dialect The resolved dialect.
*/
public JdbcEnvironmentImpl(ServiceRegistryImplementor serviceRegistry, Dialect dialect) {
this.serviceRegistry = serviceRegistry;
this.dialect = dialect;
this.sqlExceptionHelper = buildSqlExceptionHelper( dialect );
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl( this );
// make sure reserved-words, current-catalog and current-schema happen before the identifier-helper!
this.reservedWords = dialect.getKeywords();
this.currentCatalog = Identifier.toIdentifier(
serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING )
);
this.currentSchema = Identifier.toIdentifier(
serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING )
);
final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, StandardConverters.BOOLEAN, false );
// a simple temporary impl that works on H2
this.identifierHelper = new NormalizingIdentifierHelperImpl(
this,
globallyQuoteIdentifiers,
true, // storesMixedCaseQuotedIdentifiers
false, // storesLowerCaseQuotedIdentifiers
false, // storesUpperCaseQuotedIdentifiers
true, // storesUpperCaseIdentifiers
false // storesLowerCaseIdentifiers
);
// again, a simple temporary impl that works on H2
this.qualifiedObjectNameSupport = new StandardQualifiedObjectNameSupportImpl(
".",
true,
dialect.openQuote(),
dialect.closeQuote()
);
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder();
}
public JdbcEnvironmentImpl(ServiceRegistryImplementor serviceRegistry, Dialect dialect, DatabaseMetaData dbmd) throws SQLException {
this.serviceRegistry = serviceRegistry;
this.dialect = dialect;
this.sqlExceptionHelper = buildSqlExceptionHelper( dialect );
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl(
this,
StandardRefCursorSupport.supportsRefCursors( dbmd ),
dbmd.supportsNamedParameters(),
dbmd.supportsResultSetType( ResultSet.TYPE_SCROLL_INSENSITIVE ),
dbmd.supportsGetGeneratedKeys(),
dbmd.supportsBatchUpdates(),
!dbmd.dataDefinitionIgnoredInTransactions(),
dbmd.dataDefinitionCausesTransactionCommit(),
parseSQLStateType( dbmd.getSQLStateType() ),
dbmd.locatorsUpdateCopy()
);
// make sure reserved-words happen before the identifier-helper!
this.reservedWords = buildMergedReservedWords( dialect, dbmd );
final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, StandardConverters.BOOLEAN, false );
this.identifierHelper = new NormalizingIdentifierHelperImpl(
this,
globallyQuoteIdentifiers,
dbmd.storesMixedCaseQuotedIdentifiers(),
dbmd.storesLowerCaseQuotedIdentifiers(),
dbmd.storesUpperCaseQuotedIdentifiers(),
dbmd.storesUpperCaseIdentifiers(),
dbmd.storesLowerCaseIdentifiers()
);
// and that current-catalog and current-schema happen after it
this.currentCatalog = determineCurrentCatalog( dbmd );
this.currentSchema = determineCurrentSchema( dbmd );
this.qualifiedObjectNameSupport = new StandardQualifiedObjectNameSupportImpl(
dbmd.getCatalogSeparator(),
dbmd.isCatalogAtStart(),
dialect.openQuote(),
dialect.closeQuote()
);
this.typeInfoSet.addAll( TypeInfo.extractTypeInfo( dbmd ) );
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder(
serviceRegistry.getService( ConfigurationService.class ).getSettings(),
dbmd.getConnection()
);
}
private SQLStateType parseSQLStateType(int sqlStateType) {
switch ( sqlStateType ) {
case DatabaseMetaData.sqlStateSQL99 : {
return SQLStateType.SQL99;
}
case DatabaseMetaData.sqlStateXOpen : {
return SQLStateType.XOpen;
}
default : {
return SQLStateType.UNKNOWN;
}
}
}
@SuppressWarnings("deprecation")
private SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect) {
SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter();
if ( sqlExceptionConverter == null ) {
final StandardSQLExceptionConverter converter = new StandardSQLExceptionConverter();
sqlExceptionConverter = converter;
converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() );
converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) );
// todo : vary this based on extractedMetaDataSupport.getSqlStateType()
converter.addDelegate( new SQLStateConversionDelegate( dialect ) );
}
return new SqlExceptionHelper( sqlExceptionConverter );
}
private Identifier determineCurrentCatalog(DatabaseMetaData dbmd) throws SQLException {
String currentCatalogName = dbmd.getConnection().getCatalog();
if ( currentCatalogName != null ) {
// intentionally using fromMetaDataObjectName rather than fromMetaDataCatalogName !!!
return identifierHelper.fromMetaDataObjectName( currentCatalogName );
}
else {
currentCatalogName = serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING );
return Identifier.toIdentifier( currentCatalogName );
}
}
private Identifier determineCurrentSchema(DatabaseMetaData dbmd) throws SQLException {
String currentSchemaName = locateSchemaNameResolver().resolveSchemaName( dbmd.getConnection(), dialect );
if ( currentSchemaName != null ) {
// intentionally using fromMetaDataObjectName rather than fromMetaDataSchemaName !!!
return identifierHelper.fromMetaDataObjectName( currentSchemaName );
}
else {
currentSchemaName = serviceRegistry.getService( ConfigurationService.class )
.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING );
return Identifier.toIdentifier( currentSchemaName );
}
}
private SchemaNameResolver locateSchemaNameResolver() {
final Object setting = serviceRegistry.getService( ConfigurationService.class )
.getSettings()
.get( AvailableSettings.SCHEMA_NAME_RESOLVER );
try {
return serviceRegistry.getService( StrategySelector.class ).resolveDefaultableStrategy(
SchemaNameResolver.class,
setting,
DefaultSchemaNameResolver.INSTANCE
);
}
catch ( StrategySelectionException e ) {
final Throwable cause = e.getCause();
if ( ClassNotFoundException.class.isInstance( cause ) ) {
LOG.unableToLocateConfiguredSchemaNameResolver(
e.getImplementationClassName(),
cause.toString()
);
}
else if ( InvocationTargetException.class.isInstance( cause ) ) {
LOG.unableToInstantiateConfiguredSchemaNameResolver(
e.getImplementationClassName(),
InvocationTargetException.class.cast( cause ).getTargetException().toString() );
}
else {
LOG.unableToInstantiateConfiguredSchemaNameResolver(
e.getImplementationClassName(),
cause.toString() );
}
return null;
}
}
private Set<String> buildMergedReservedWords(Dialect dialect, DatabaseMetaData dbmd) throws SQLException {
Set<String> reservedWords = new HashSet<String>();
reservedWords.addAll( dialect.getKeywords() );
// todo : do we need to explicitly handle SQL:2003 keywords?
reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) );
return reservedWords;
}
@Override
public Dialect getDialect() {
return dialect;
}
@Override
public ExtractedDatabaseMetaData getExtractedDatabaseMetaData() {
return extractedMetaDataSupport;
}
@Override
public Identifier getCurrentCatalog() {
return currentCatalog;
}
@Override
public Identifier getCurrentSchema() {
return currentSchema;
}
@Override
public QualifiedObjectNameSupport getQualifiedObjectNameSupport() {
return qualifiedObjectNameSupport;
}
@Override
public IdentifierHelper getIdentifierHelper() {
return identifierHelper;
}
@Override
public Set<String> getReservedWords() {
return reservedWords;
}
@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return sqlExceptionHelper;
}
@Override
public LobCreatorBuilder getLobCreatorBuilder() {
return lobCreatorBuilder;
}
@Override
public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) {
for ( TypeInfo typeInfo : typeInfoSet ) {
if ( typeInfo.getJdbcTypeCode() == jdbcTypeCode ) {
return typeInfo;
}
}
return null;
}
@Override
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
}

View File

@ -0,0 +1,214 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.internal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* @author Steve Ebersole
*/
public class JdbcEnvironmentInitiator implements StandardServiceInitiator<JdbcEnvironment> {
private static final CoreMessageLogger log = Logger.getMessageLogger(
CoreMessageLogger.class,
JdbcEnvironmentInitiator.class.getName()
);
public static final JdbcEnvironmentInitiator INSTANCE = new JdbcEnvironmentInitiator();
@Override
public Class<JdbcEnvironment> getServiceInitiated() {
return JdbcEnvironment.class;
}
@Override
public JdbcEnvironment initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
final DialectFactory dialectFactory = registry.getService( DialectFactory.class );
// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
// The need for it is intended to be alleviated with future development, thus it is
// not defined as an Environment constant...
//
// it is used to control whether we should consult the JDBC metadata to determine
// certain Settings default values; it is useful to *not* do this when the database
// may not be available (mainly in tools usage).
boolean useJdbcMetadata = ConfigurationHelper.getBoolean(
"hibernate.temp.use_jdbc_metadata_defaults",
configurationValues,
true
);
if ( useJdbcMetadata ) {
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( configurationValues, registry );
try {
final Connection connection = jdbcConnectionAccess.obtainConnection();
try {
final DatabaseMetaData dbmd = connection.getMetaData();
if ( log.isDebugEnabled() ) {
log.debugf(
"Database ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDatabaseProductName(),
dbmd.getDatabaseProductVersion(),
dbmd.getDatabaseMajorVersion(),
dbmd.getDatabaseMinorVersion()
);
log.debugf(
"Driver ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
dbmd.getDriverName(),
dbmd.getDriverVersion(),
dbmd.getDriverMajorVersion(),
dbmd.getDriverMinorVersion()
);
log.debugf( "JDBC version : %s.%s", dbmd.getJDBCMajorVersion(), dbmd.getJDBCMinorVersion() );
}
Dialect dialect = dialectFactory.buildDialect(
configurationValues,
new DialectResolutionInfoSource() {
@Override
public DialectResolutionInfo getDialectResolutionInfo() {
try {
return new DatabaseMetaDataDialectResolutionInfoAdapter( connection.getMetaData() );
}
catch ( SQLException sqlException ) {
throw new HibernateException(
"Unable to access java.sql.DatabaseMetaData to determine appropriate Dialect to use",
sqlException
);
}
}
}
);
return new JdbcEnvironmentImpl(
registry,
dialect,
dbmd
);
}
catch (SQLException e) {
log.unableToObtainConnectionMetadata( e.getMessage() );
}
finally {
try {
jdbcConnectionAccess.releaseConnection( connection );
}
catch (SQLException ignore) {
}
}
}
catch (Exception e) {
log.unableToObtainConnectionToQueryMetadata( e.getMessage() );
}
}
// if we get here, either we were asked to not use JDBC metadata or accessing the JDBC metadata failed.
return new JdbcEnvironmentImpl( registry, dialectFactory.buildDialect( configurationValues, null ) );
}
private JdbcConnectionAccess buildJdbcConnectionAccess(Map configValues, ServiceRegistryImplementor registry) {
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues );
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class );
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
}
else {
final MultiTenantConnectionProvider multiTenantConnectionProvider = registry.getService( MultiTenantConnectionProvider.class );
return new MultiTenantConnectionProviderJdbcConnectionAccess( multiTenantConnectionProvider );
}
}
private static class ConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final ConnectionProvider connectionProvider;
public ConnectionProviderJdbcConnectionAccess(ConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
private static class MultiTenantConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final MultiTenantConnectionProvider connectionProvider;
public MultiTenantConnectionProviderJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getAnyConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.releaseAnyConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
}

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.internal;
package org.hibernate.engine.jdbc.env.internal;
import java.lang.reflect.Method;
import java.sql.Connection;
@ -34,6 +34,7 @@ import org.hibernate.engine.jdbc.ContextualLobCreator;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.NonContextualLobCreator;
import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
@ -44,23 +45,40 @@ import org.jboss.logging.Logger;
*
* @author Steve Ebersole
*/
public class LobCreatorBuilder {
public class LobCreatorBuilderImpl implements LobCreatorBuilder {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
LobCreatorBuilder.class.getName()
LobCreatorBuilderImpl.class.getName()
);
private boolean useContextualLobCreation;
private final boolean useContextualLobCreation;
private LobCreatorBuilderImpl(boolean useContextualLobCreation) {
this.useContextualLobCreation = useContextualLobCreation;
}
// factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* The public factory method for obtaining the appropriate (according to given JDBC {@link java.sql.Connection}.
* The public factory method for obtaining the appropriate LOB creator (according to given
* JDBC {@link java.sql.Connection}).
*
* @param configValues The map of settings
* @param jdbcConnection A JDBC {@link java.sql.Connection} which can be used to gauge the drivers level of support,
* specifically for creating LOB references.
*/
public LobCreatorBuilder(Map configValues, Connection jdbcConnection) {
this.useContextualLobCreation = useContextualLobCreation( configValues, jdbcConnection );
public static LobCreatorBuilderImpl makeLobCreatorBuilder(Map configValues, Connection jdbcConnection) {
return new LobCreatorBuilderImpl( useContextualLobCreation( configValues, jdbcConnection ) );
}
/**
* For used when JDBC Connection is not available.
*
* @return Appropriate LobCreatorBuilder
*/
public static LobCreatorBuilderImpl makeLobCreatorBuilder() {
LOG.disablingContextualLOBCreationSinceConnectionNull();
return new LobCreatorBuilderImpl( false );
}
private static final Class[] NO_ARG_SIG = new Class[0];

View File

@ -0,0 +1,217 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.internal;
import org.jboss.logging.Logger;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.relational.Identifier;
/**
* @author Steve Ebersole
*/
public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
private static final Logger log = Logger.getLogger( NormalizingIdentifierHelperImpl.class );
private final JdbcEnvironment jdbcEnvironment;
private final boolean globallyQuoteIdentifiers;
private final boolean storesMixedCaseQuotedIdentifiers;
private final boolean storesLowerCaseQuotedIdentifiers;
private final boolean storesUpperCaseQuotedIdentifiers;
private final boolean storesUpperCaseIdentifiers;
private final boolean storesLowerCaseIdentifiers;
public NormalizingIdentifierHelperImpl(
JdbcEnvironment jdbcEnvironment,
boolean globallyQuoteIdentifiers,
boolean storesMixedCaseQuotedIdentifiers,
boolean storesLowerCaseQuotedIdentifiers,
boolean storesUpperCaseQuotedIdentifiers,
boolean storesUpperCaseIdentifiers,
boolean storesLowerCaseIdentifiers) {
this.jdbcEnvironment = jdbcEnvironment;
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
this.storesMixedCaseQuotedIdentifiers = storesMixedCaseQuotedIdentifiers;
this.storesLowerCaseQuotedIdentifiers = storesLowerCaseQuotedIdentifiers;
this.storesUpperCaseQuotedIdentifiers = storesUpperCaseQuotedIdentifiers;
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in mixed, upper and lower case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and upper case" );
}
else if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and lower case" );
}
if ( storesUpperCaseIdentifiers && storesLowerCaseIdentifiers ) {
log.warn( "JDBC Driver reports it stores non-quoted identifiers in both upper and lower case" );
}
if ( storesUpperCaseIdentifiers && storesUpperCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in upper case" );
}
if ( storesLowerCaseIdentifiers && storesLowerCaseQuotedIdentifiers ) {
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in lower case" );
}
}
// In the DatabaseMetaData method params for catalog and schema name have the following meaning:
// 1) <""> means to match things "without a catalog/schema"
// 2) <null> means to not limit results based on this field
//
// todo : not sure how "without a catalog/schema" is interpreted. Current?
@Override
public String toMetaDataCatalogName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentCatalog>
return jdbcEnvironment.getCurrentCatalog() == null ? null : jdbcEnvironment.getCurrentCatalog().getText();
}
return toText( identifier );
}
private String toText(Identifier identifier) {
if ( identifier == null ) {
throw new IllegalArgumentException( "Identifier cannot be null; bad usage" );
}
if ( identifier.isQuoted() && storesMixedCaseQuotedIdentifiers ) {
return identifier.getText();
}
else if ( ( identifier.isQuoted() && storesUpperCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesUpperCaseIdentifiers ) ) {
return StringHelper.toUpperCase( identifier.getText() );
}
else if ( ( identifier.isQuoted() && storesLowerCaseQuotedIdentifiers )
|| ( !identifier.isQuoted() && storesLowerCaseIdentifiers ) ) {
return StringHelper.toLowerCase( identifier.getText() );
}
return identifier.getText();
}
@Override
public String toMetaDataSchemaName(Identifier identifier) {
if ( identifier == null ) {
// todo : not sure if this is interpreted as <""> or <currentSchema>
return jdbcEnvironment.getCurrentSchema() == null ? null : jdbcEnvironment.getCurrentSchema().getText();
}
return toText( identifier );
}
@Override
public String toMetaDataObjectName(Identifier identifier) {
if ( identifier == null ) {
// if this method was called, the value is needed
throw new IllegalArgumentException( );
}
return toText( identifier );
}
@Override
public Identifier fromMetaDataCatalogName(String catalogName) {
if ( catalogName == null ) {
return null;
}
if ( jdbcEnvironment.getCurrentCatalog() == null
|| catalogName.equals( jdbcEnvironment.getCurrentCatalog().getText() ) ) {
return null;
}
return toIdentifier( catalogName );
// note really sure the best way to know (can you?) whether the identifier is quoted
}
public Identifier toIdentifier(String text) {
if ( globallyQuoteIdentifiers ) {
return Identifier.toIdentifier( text, true );
}
// lovely decipher of whether the incoming value represents a quoted identifier...
final boolean isUpperCase = text.toUpperCase().equals( text );
final boolean isLowerCase = text.toLowerCase().equals( text );
final boolean isMixedCase = ! isLowerCase && ! isUpperCase;
if ( jdbcEnvironment.getReservedWords().contains( text ) ) {
// unequivocally it needs to be quoted...
return Identifier.toIdentifier( text, true );
}
if ( storesMixedCaseQuotedIdentifiers && isMixedCase ) {
return Identifier.toIdentifier( text, true );
}
if ( storesLowerCaseQuotedIdentifiers && isLowerCase ) {
return Identifier.toIdentifier( text, true );
}
if ( storesUpperCaseQuotedIdentifiers && isUpperCase ) {
return Identifier.toIdentifier( text, true );
}
return Identifier.toIdentifier( text );
}
@Override
public Identifier toIdentifier(String text, boolean quoted) {
return globallyQuoteIdentifiers
? Identifier.toIdentifier( text, true )
: Identifier.toIdentifier( text, quoted );
}
@Override
public Identifier fromMetaDataSchemaName(String schemaName) {
if ( schemaName == null ) {
return null;
}
if ( jdbcEnvironment.getCurrentSchema() == null
|| schemaName.equals( jdbcEnvironment.getCurrentSchema().getText() ) ) {
return null;
}
return toIdentifier( schemaName );
}
@Override
public Identifier fromMetaDataObjectName(String objectName) {
if ( objectName == null ) {
return null;
}
return toIdentifier( objectName );
}
}

View File

@ -21,11 +21,13 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.spi;
package org.hibernate.engine.jdbc.env.spi;
import java.util.LinkedHashSet;
import java.util.Set;
import org.hibernate.engine.jdbc.spi.TypeInfo;
/**
* Information extracted from {@link java.sql.DatabaseMetaData} regarding what the JDBC driver reports as
* being supported or not. Obviously {@link java.sql.DatabaseMetaData} reports many things, these are a few in
@ -36,22 +38,11 @@ import java.util.Set;
@SuppressWarnings( {"UnusedDeclaration"})
public interface ExtractedDatabaseMetaData {
/**
* Which specification do the reported SQLState codes follow?
* Obtain the JDBC Environment from which this metadata came.
*
* @return The JDBC environment
*/
public enum SQLStateType {
/**
* The reported codes follow the X/Open spec
*/
XOpen,
/**
* The reported codes follow the SQL spec
*/
SQL99,
/**
* It is unknown. Might follow another spec completely, or be a mixture.
*/
UNKOWN
}
public JdbcEnvironment getJdbcEnvironment();
/**
* Does the driver report supporting named parameters?
@ -116,15 +107,6 @@ public interface ExtractedDatabaseMetaData {
*/
public boolean doesDataDefinitionCauseTransactionCommit();
/**
* Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver.
*
* @return The extra keywords used by this database.
*
* @see java.sql.DatabaseMetaData#getSQLKeywords()
*/
public Set<String> getExtraKeywords();
/**
* Retrieve the type of codes the driver says it uses for {@code SQLState}. They might follow either
* the X/Open standard or the SQL92 standard.
@ -143,27 +125,4 @@ public interface ExtractedDatabaseMetaData {
* @see java.sql.DatabaseMetaData#locatorsUpdateCopy()
*/
public boolean doesLobLocatorUpdateCopy();
/**
* Retrieve the name of the schema in effect when we connected to the database.
*
* @return The schema name
*/
public String getConnectionSchemaName();
/**
* Retrieve the name of the catalog in effect when we connected to the database.
*
* @return The catalog name
*/
public String getConnectionCatalogName();
/**
* Set of type info reported by the driver.
*
* @return The type information obtained from the driver.
*
* @see java.sql.DatabaseMetaData#getTypeInfo()
*/
public LinkedHashSet<TypeInfo> getTypeInfoSet();
}

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
import org.hibernate.metamodel.spi.relational.Identifier;
/**
* Helper for handling {@link Identifier} instances.
*
* @author Steve Ebersole
*/
public interface IdentifierHelper {
/**
* Generate an {@link Identifier} instance from its simple name
*
* @param text The text
*
* @return The identifier form of the name.
*/
public Identifier toIdentifier(String text);
/**
* Generate an {@link Identifier} instance from its simple name and explicitly whether it is quoted or not
* (although note that 'globally quoted identifiers' setting can still cause returned Identifiers to be quoted
* even if {@code false} is passed in here).
*
* @param text The name
* @param quoted Is the identifier to be quoted explicitly.
*
* @return The identifier form of the name.
*/
public Identifier toIdentifier(String text, boolean quoted);
public String toMetaDataCatalogName(Identifier identifier);
public String toMetaDataSchemaName(Identifier identifier);
public String toMetaDataObjectName(Identifier identifier);
public Identifier fromMetaDataCatalogName(String catalogName);
public Identifier fromMetaDataSchemaName(String schemaName);
public Identifier fromMetaDataObjectName(String objectName);
}

View File

@ -0,0 +1,124 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
import java.util.Set;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.service.Service;
import org.hibernate.service.ServiceRegistry;
/**
* Initial look at this concept we keep talking about with merging information from {@link java.sql.DatabaseMetaData}
* and {@link org.hibernate.dialect.Dialect}
*
* @author Steve Ebersole
*/
public interface JdbcEnvironment extends Service {
/**
* Get the dialect for this environment.
*
* @return The dialect.
*/
public Dialect getDialect();
/**
* Access to the bits of information we pulled off the JDBC {@link java.sql.DatabaseMetaData} (that did not get
* "interpreted" into the helpers/delegates available here).
*
* @return The values extracted from JDBC DatabaseMetaData
*/
public ExtractedDatabaseMetaData getExtractedDatabaseMetaData();
/**
* Get the current database catalog. Typically will come from either {@link java.sql.Connection#getCatalog()}
* or {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}.
*
* @return The current catalog.
*/
public Identifier getCurrentCatalog();
/**
* Get the current database catalog. Typically will come from either
* {@link SchemaNameResolver#resolveSchemaName(java.sql.Connection, org.hibernate.dialect.Dialect)} or
* {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}.
*
* @return The current schema
*/
public Identifier getCurrentSchema();
/**
* Obtain support for reading and writing qualified object names.
*
* @return Qualified name support.
*/
public QualifiedObjectNameSupport getQualifiedObjectNameSupport();
/**
* Obtain the helper for dealing with identifiers in this environment.
*
* @return The identifier helper.
*/
public IdentifierHelper getIdentifierHelper();
/**
* Get the complete set of reserved words for this environment. These are significant because they represent
* the complete set of terms that MUST BE quoted if used as identifiers. This allows us to apply auto-quoting
* in the metamodel based on these terms.
*
* Note that the standard IdentifierHelper returned by {@link #getIdentifierHelper()} already accounts for
* auto-quoting :) yaay!
*
* @return Reserved words
*/
public Set<String> getReservedWords();
/**
* Obtain the helper for dealing with JDBC {@link java.sql.SQLException} faults.
*
* @return This environment's helper.
*/
public SqlExceptionHelper getSqlExceptionHelper();
/**
* Retrieve the delegate for building {@link org.hibernate.engine.jdbc.LobCreator} instances.
*
* @return The LobCreator builder.
*/
public LobCreatorBuilder getLobCreatorBuilder();
/**
* Find type information for the type identified by the given "JDBC type code".
*
* @param jdbcTypeCode The JDBC type code.
*
* @return The corresponding type info.
*/
public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode);
public ServiceRegistry getServiceRegistry();
}

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
/**
* @author Steve Ebersole
*/
public interface LobCreatorBuilder {
LobCreator buildLobCreator(LobCreationContext lobCreationContext);
}

View File

@ -0,0 +1,55 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
import org.hibernate.metamodel.spi.relational.ObjectName;
/**
* Defines support for reading and writing qualified object names to and from the database. Generally speaking
* Hibernate itself only uses {@link #formatName}. Most times when it is "parsing" object names it is coming from
* mappings, in which case we expect simple dot-separated syntax and apply {@link ObjectName#parse}
*
* @author Steve Ebersole
*/
public interface QualifiedObjectNameSupport {
/**
* Performs formatting of an ObjectName to its String representation
*
* @param objectName The object name to be formatted.
*
* @return The dialect specific string form of the name.
*/
public String formatName(ObjectName objectName);
/**
* Parse a String representation of an Object name to its ObjectName. Note that this specifically
* attempts to parse the text as if coming from the database. Mapping forms always use
* the form {@code <schema>.<catalog>.<name>}, parsing such names should just use {@link ObjectName#parse}
*
* @param text The object name text
*
* @return The parsed ObjectName
*/
public ObjectName parseName(String text);
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
/**
* Enum interpretation of the valid values from {@link java.sql.DatabaseMetaData#getSQLStateType()}
*
* @author Steve Ebersole
*/
public enum SQLStateType {
/**
* The reported codes follow the X/Open spec
*/
XOpen,
/**
* The reported codes follow the SQL spec
*/
SQL99,
/**
* It is unknown. Might follow another spec completely, or be a mixture.
*/
UNKNOWN
}

View File

@ -0,0 +1,46 @@
/*
* 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.engine.jdbc.env.spi;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.dialect.Dialect;
/**
* Contract for resolving the schema of a {@link Connection}.
*
* @author Steve Ebersole
*/
public interface SchemaNameResolver {
/**
* Given a JDBC {@link Connection}, resolve the name of the schema (if one) to which it connects.
*
* @param connection The JDBC connection
* @param dialect The Dialect
*
* @return The name of the schema (may be null).
*/
public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException;
}

View File

@ -0,0 +1,144 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.jdbc.env.spi;
import java.util.regex.Pattern;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.spi.relational.IllegalIdentifierException;
import org.hibernate.metamodel.spi.relational.ObjectName;
/**
* @author Steve Ebersole
*/
public class StandardQualifiedObjectNameSupportImpl implements QualifiedObjectNameSupport {
public static final char DEFAULT_QUOTE_START = '\'';
public static final char DEFAULT_QUOTE_END = '\'';
public static final String DEFAULT_CATALOG_SEPARATOR = ".";
private final String catalogSeparator;
private final boolean catalogAfterName;
private final char quotedStart;
private final char quotedEnd;
private final Pattern splitPattern;
public StandardQualifiedObjectNameSupportImpl(
String catalogSeparator,
boolean catalogAfterName,
char quotedStart,
char quotedEnd) {
this.catalogSeparator = catalogSeparator;
this.catalogAfterName = catalogAfterName;
this.quotedStart = quotedStart;
this.quotedEnd = quotedEnd;
splitPattern = ".".equals( catalogSeparator )
? Pattern.compile( Pattern.quote( "." ) )
: Pattern.compile( "[\\." + catalogSeparator + "]" );
}
public StandardQualifiedObjectNameSupportImpl() {
this( DEFAULT_CATALOG_SEPARATOR, false, DEFAULT_QUOTE_START, DEFAULT_QUOTE_END );
}
public StandardQualifiedObjectNameSupportImpl(String catalogSeparator, boolean catalogAfterName, Dialect dialect) {
this( catalogSeparator, catalogAfterName, dialect.openQuote(), dialect.closeQuote() );
}
public StandardQualifiedObjectNameSupportImpl(Dialect dialect) {
this( DEFAULT_CATALOG_SEPARATOR, false, dialect );
}
public StandardQualifiedObjectNameSupportImpl(String catalogSeparator, boolean catalogAfterName) {
this( catalogSeparator, catalogAfterName, DEFAULT_QUOTE_START, DEFAULT_QUOTE_END );
}
@Override
public String formatName(ObjectName objectName) {
StringBuilder buffer = new StringBuilder();
if ( ! catalogAfterName ) {
if ( objectName.getCatalog() != null ) {
buffer.append( objectName.getCatalog().getText( quotedStart, quotedEnd ) )
.append( catalogSeparator );
}
}
if ( objectName.getSchema() != null ) {
buffer.append( objectName.getSchema().getText( quotedStart, quotedEnd ) ).append( '.' );
}
buffer.append( objectName.getName().getText( quotedStart, quotedEnd ) );
if ( catalogAfterName ) {
if ( objectName.getCatalog() != null ) {
buffer.append( catalogSeparator )
.append( objectName.getCatalog().getText( quotedStart, quotedEnd ) );
}
}
return buffer.toString();
}
@Override
public ObjectName parseName(String text) {
if ( text == null ) {
throw new IllegalIdentifierException( "Object name must be specified" );
}
String catalogName = null;
String schemaName = null;
String localObjectName;
final String[] tokens = splitPattern.split( text );
if ( tokens.length == 0 || tokens.length == 1 ) {
// we have just a local name...
localObjectName = text;
}
else if ( tokens.length == 2 ) {
// we have 'something.name', no real way to know if something is a catalog or schema
// but thats ok based on the way we implement Database... so assume schema
schemaName = tokens[0];
localObjectName = tokens[1];
}
else if ( tokens.length == 3 ) {
if ( catalogAfterName ) {
schemaName = tokens[0];
localObjectName = tokens[1];
catalogName = tokens[2];
}
else {
catalogName = tokens[0];
schemaName = tokens[1];
localObjectName = tokens[2];
}
}
else {
throw new HibernateException( "Unable to parse object name: " + text );
}
return new ObjectName( catalogName, schemaName, localObjectName );
}
}

View File

@ -23,45 +23,22 @@
*/
package org.hibernate.engine.jdbc.internal;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport;
import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter;
import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource;
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
import org.hibernate.engine.jdbc.spi.SchemaNameResolver;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.jdbc.spi.TypeInfo;
import org.hibernate.exception.internal.SQLExceptionTypeDelegate;
import org.hibernate.exception.internal.SQLStateConversionDelegate;
import org.hibernate.exception.internal.StandardSQLExceptionConverter;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.ServiceRegistryAwareService;
@ -76,13 +53,10 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JdbcServicesImpl.class );
private ServiceRegistryImplementor serviceRegistry;
private JdbcEnvironment jdbcEnvironment;
private Dialect dialect;
private ConnectionProvider connectionProvider;
private SqlStatementLogger sqlStatementLogger;
private SqlExceptionHelper sqlExceptionHelper;
private ExtractedDatabaseMetaData extractedMetaDataSupport;
private LobCreatorBuilder lobCreatorBuilder;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
@ -91,389 +65,17 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
@Override
public void configure(Map configValues) {
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( configValues );
final DialectFactory dialectFactory = serviceRegistry.getService( DialectFactory.class );
this.jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
Dialect dialect = null;
LobCreatorBuilder lobCreatorBuilder = null;
boolean metaSupportsRefCursors = false;
boolean metaSupportsNamedParams = false;
boolean metaSupportsScrollable = false;
boolean metaSupportsGetGeneratedKeys = false;
boolean metaSupportsBatchUpdates = false;
boolean metaReportsDDLCausesTxnCommit = false;
boolean metaReportsDDLInTxnSupported = true;
String extraKeywordsString = "";
int sqlStateType = -1;
boolean lobLocatorUpdateCopy = false;
String catalogName = null;
String schemaName = null;
final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
// 'hibernate.temp.use_jdbc_metadata_defaults' is a temporary magic value.
// The need for it is intended to be alleviated with future development, thus it is
// not defined as an Environment constant...
//
// it is used to control whether we should consult the JDBC metadata to determine
// certain Settings default values; it is useful to *not* do this when the database
// may not be available (mainly in tools usage).
final boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true );
if ( useJdbcMetadata ) {
try {
final Connection connection = jdbcConnectionAccess.obtainConnection();
try {
final DatabaseMetaData meta = connection.getMetaData();
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Database ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
meta.getDatabaseProductName(),
meta.getDatabaseProductVersion(),
meta.getDatabaseMajorVersion(),
meta.getDatabaseMinorVersion()
);
LOG.debugf(
"Driver ->\n"
+ " name : %s\n"
+ " version : %s\n"
+ " major : %s\n"
+ " minor : %s",
meta.getDriverName(),
meta.getDriverVersion(),
meta.getDriverMajorVersion(),
meta.getDriverMinorVersion()
);
LOG.debugf( "JDBC version : %s.%s", meta.getJDBCMajorVersion(), meta.getJDBCMinorVersion() );
}
metaSupportsRefCursors = StandardRefCursorSupport.supportsRefCursors( meta );
metaSupportsNamedParams = meta.supportsNamedParameters();
metaSupportsScrollable = meta.supportsResultSetType( ResultSet.TYPE_SCROLL_INSENSITIVE );
metaSupportsBatchUpdates = meta.supportsBatchUpdates();
metaReportsDDLCausesTxnCommit = meta.dataDefinitionCausesTransactionCommit();
metaReportsDDLInTxnSupported = !meta.dataDefinitionIgnoredInTransactions();
metaSupportsGetGeneratedKeys = meta.supportsGetGeneratedKeys();
extraKeywordsString = meta.getSQLKeywords();
sqlStateType = meta.getSQLStateType();
lobLocatorUpdateCopy = meta.locatorsUpdateCopy();
typeInfoSet.addAll( TypeInfo.extractTypeInfo( meta ) );
dialect = dialectFactory.buildDialect(
configValues,
new DialectResolutionInfoSource() {
@Override
public DialectResolutionInfo getDialectResolutionInfo() {
try {
return new DatabaseMetaDataDialectResolutionInfoAdapter( connection.getMetaData() );
}
catch ( SQLException sqlException ) {
throw new HibernateException(
"Unable to access java.sql.DatabaseMetaData to determine appropriate Dialect to use",
sqlException
);
}
}
}
);
catalogName = connection.getCatalog();
final SchemaNameResolver schemaNameResolver = determineExplicitSchemaNameResolver( configValues );
if ( schemaNameResolver == null ) {
// todo : add dialect method
// schemaNameResolver = dialect.getSchemaNameResolver();
}
if ( schemaNameResolver != null ) {
schemaName = schemaNameResolver.resolveSchemaName( connection );
}
lobCreatorBuilder = new LobCreatorBuilder( configValues, connection );
}
catch ( SQLException sqle ) {
LOG.unableToObtainConnectionMetadata( sqle.getMessage() );
}
finally {
if ( connection != null ) {
jdbcConnectionAccess.releaseConnection( connection );
}
}
}
catch ( SQLException sqle ) {
LOG.unableToObtainConnectionToQueryMetadata( sqle.getMessage() );
dialect = dialectFactory.buildDialect( configValues, null );
}
catch ( UnsupportedOperationException uoe ) {
// user supplied JDBC connections
dialect = dialectFactory.buildDialect( configValues, null );
}
}
else {
dialect = dialectFactory.buildDialect( configValues, null );
}
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues );
this.connectionProvider = MultiTenancyStrategy.NONE == multiTenancyStrategy ?
serviceRegistry.getService( ConnectionProvider.class ) :
null;
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false );
final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false );
this.dialect = dialect;
this.lobCreatorBuilder = (
lobCreatorBuilder == null ?
new LobCreatorBuilder( configValues, null ) :
lobCreatorBuilder
);
this.sqlStatementLogger = new SqlStatementLogger( showSQL, formatSQL );
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl(
metaSupportsRefCursors,
metaSupportsNamedParams,
metaSupportsScrollable,
metaSupportsGetGeneratedKeys,
metaSupportsBatchUpdates,
metaReportsDDLInTxnSupported,
metaReportsDDLCausesTxnCommit,
parseKeywords( extraKeywordsString ),
parseSQLStateType( sqlStateType ),
lobLocatorUpdateCopy,
schemaName,
catalogName,
typeInfoSet
);
SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter();
if ( sqlExceptionConverter == null ) {
final StandardSQLExceptionConverter converter = new StandardSQLExceptionConverter();
sqlExceptionConverter = converter;
converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() );
converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) );
// todo : vary this based on extractedMetaDataSupport.getSqlStateType()
converter.addDelegate( new SQLStateConversionDelegate( dialect ) );
}
this.sqlExceptionHelper = new SqlExceptionHelper( sqlExceptionConverter );
}
private JdbcConnectionAccess buildJdbcConnectionAccess(Map configValues) {
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues );
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
}
else {
connectionProvider = null;
final MultiTenantConnectionProvider multiTenantConnectionProvider = serviceRegistry.getService( MultiTenantConnectionProvider.class );
return new MultiTenantConnectionProviderJdbcConnectionAccess( multiTenantConnectionProvider );
}
}
private static class ConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final ConnectionProvider connectionProvider;
public ConnectionProviderJdbcConnectionAccess(ConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
private static class MultiTenantConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
private final MultiTenantConnectionProvider connectionProvider;
public MultiTenantConnectionProviderJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) {
this.connectionProvider = connectionProvider;
}
@Override
public Connection obtainConnection() throws SQLException {
return connectionProvider.getAnyConnection();
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
connectionProvider.releaseAnyConnection( connection );
}
@Override
public boolean supportsAggressiveRelease() {
return connectionProvider.supportsAggressiveRelease();
}
}
/**
* A constant naming the setting used to identify the {@link SchemaNameResolver} to use
* <p/>
* TODO : add to Environment
*/
public static final String SCHEMA_NAME_RESOLVER = "hibernate.schema_name_resolver";
private SchemaNameResolver determineExplicitSchemaNameResolver(Map configValues) {
final Object setting = configValues.get( SCHEMA_NAME_RESOLVER );
if ( SchemaNameResolver.class.isInstance( setting ) ) {
return (SchemaNameResolver) setting;
}
final String resolverClassName = (String) setting;
if ( resolverClassName != null ) {
try {
final Class resolverClass = ReflectHelper.classForName( resolverClassName, getClass() );
return (SchemaNameResolver) ReflectHelper.getDefaultConstructor( resolverClass ).newInstance();
}
catch ( ClassNotFoundException e ) {
LOG.unableToLocateConfiguredSchemaNameResolver( resolverClassName, e.toString() );
}
catch ( InvocationTargetException e ) {
LOG.unableToInstantiateConfiguredSchemaNameResolver( resolverClassName, e.getTargetException().toString() );
}
catch ( Exception e ) {
LOG.unableToInstantiateConfiguredSchemaNameResolver( resolverClassName, e.toString() );
}
}
return null;
}
private Set<String> parseKeywords(String extraKeywordsString) {
final Set<String> keywordSet = new HashSet<String>();
keywordSet.addAll( Arrays.asList( extraKeywordsString.split( "," ) ) );
return keywordSet;
}
private ExtractedDatabaseMetaData.SQLStateType parseSQLStateType(int sqlStateType) {
switch ( sqlStateType ) {
case DatabaseMetaData.sqlStateSQL99 : {
return ExtractedDatabaseMetaData.SQLStateType.SQL99;
}
case DatabaseMetaData.sqlStateXOpen : {
return ExtractedDatabaseMetaData.SQLStateType.XOpen;
}
default : {
return ExtractedDatabaseMetaData.SQLStateType.UNKOWN;
}
}
}
private static class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData {
private final boolean supportsRefCursors;
private final boolean supportsNamedParameters;
private final boolean supportsScrollableResults;
private final boolean supportsGetGeneratedKeys;
private final boolean supportsBatchUpdates;
private final boolean supportsDataDefinitionInTransaction;
private final boolean doesDataDefinitionCauseTransactionCommit;
private final Set<String> extraKeywords;
private final SQLStateType sqlStateType;
private final boolean lobLocatorUpdateCopy;
private final String connectionSchemaName;
private final String connectionCatalogName;
private final LinkedHashSet<TypeInfo> typeInfoSet;
private ExtractedDatabaseMetaDataImpl(
boolean supportsRefCursors,
boolean supportsNamedParameters,
boolean supportsScrollableResults,
boolean supportsGetGeneratedKeys,
boolean supportsBatchUpdates,
boolean supportsDataDefinitionInTransaction,
boolean doesDataDefinitionCauseTransactionCommit,
Set<String> extraKeywords,
SQLStateType sqlStateType,
boolean lobLocatorUpdateCopy,
String connectionSchemaName,
String connectionCatalogName,
LinkedHashSet<TypeInfo> typeInfoSet) {
this.supportsRefCursors = supportsRefCursors;
this.supportsNamedParameters = supportsNamedParameters;
this.supportsScrollableResults = supportsScrollableResults;
this.supportsGetGeneratedKeys = supportsGetGeneratedKeys;
this.supportsBatchUpdates = supportsBatchUpdates;
this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction;
this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit;
this.extraKeywords = extraKeywords;
this.sqlStateType = sqlStateType;
this.lobLocatorUpdateCopy = lobLocatorUpdateCopy;
this.connectionSchemaName = connectionSchemaName;
this.connectionCatalogName = connectionCatalogName;
this.typeInfoSet = typeInfoSet;
}
@Override
public boolean supportsRefCursors() {
return supportsRefCursors;
}
@Override
public boolean supportsNamedParameters() {
return supportsNamedParameters;
}
@Override
public boolean supportsScrollableResults() {
return supportsScrollableResults;
}
@Override
public boolean supportsGetGeneratedKeys() {
return supportsGetGeneratedKeys;
}
@Override
public boolean supportsBatchUpdates() {
return supportsBatchUpdates;
}
@Override
public boolean supportsDataDefinitionInTransaction() {
return supportsDataDefinitionInTransaction;
}
@Override
public boolean doesDataDefinitionCauseTransactionCommit() {
return doesDataDefinitionCauseTransactionCommit;
}
@Override
public Set<String> getExtraKeywords() {
return extraKeywords;
}
@Override
public SQLStateType getSqlStateType() {
return sqlStateType;
}
@Override
public boolean doesLobLocatorUpdateCopy() {
return lobLocatorUpdateCopy;
}
@Override
public String getConnectionSchemaName() {
return connectionSchemaName;
}
@Override
public String getConnectionCatalogName() {
return connectionCatalogName;
}
@Override
public LinkedHashSet<TypeInfo> getTypeInfoSet() {
return typeInfoSet;
}
}
@Override
@ -488,26 +90,30 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return sqlExceptionHelper;
return jdbcEnvironment == null ? null : jdbcEnvironment.getSqlExceptionHelper();
}
@Override
public Dialect getDialect() {
return dialect;
return jdbcEnvironment == null ? null : jdbcEnvironment.getDialect();
}
@Override
public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
return extractedMetaDataSupport;
}
return jdbcEnvironment == null ? null : jdbcEnvironment.getExtractedDatabaseMetaData(); }
@Override
public LobCreator getLobCreator(LobCreationContext lobCreationContext) {
return lobCreatorBuilder.buildLobCreator( lobCreationContext );
return jdbcEnvironment == null ? null : jdbcEnvironment.getLobCreatorBuilder().buildLobCreator( lobCreationContext );
}
@Override
public ResultSetWrapper getResultSetWrapper() {
return ResultSetWrapperImpl.INSTANCE;
}
@Override
public JdbcEnvironment getJdbcEnvironment() {
return jdbcEnvironment;
}
}

View File

@ -27,6 +27,8 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.service.Service;
/**
@ -90,4 +92,6 @@ public interface JdbcServices extends Service {
* @return The ResultSet wrapper.
*/
public ResultSetWrapper getResultSetWrapper();
public JdbcEnvironment getJdbcEnvironment();
}

View File

@ -25,7 +25,7 @@ package org.hibernate.engine.spi;
import org.hibernate.cfg.Configuration;
import org.hibernate.internal.CacheImpl;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;

View File

@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.engine.spi;
/**
* @author Steve Ebersole
* @author Gail Badner
*/
public class SyntheticAttributeHelper {
public static final String SYNTHETIC_COMPOSITE_ID_ATTRIBUTE_NAME = "_identifierMapper";
private static final String BACKREF_ATTRIBUTE_NAME_PREFIX = "_";
private static final String BACKREF_ATTRIBUTE_NAME_SUFFIX = "BackRef";
private static final String INDEX_BACKREF_ATTRIBUTE_NAME_SUFFIX = "IndexBackRef";
public static String createBackRefAttributeName(String pluralAttributeRole) {
return createSyntheticAttributeName(
pluralAttributeRole,
BACKREF_ATTRIBUTE_NAME_PREFIX,
BACKREF_ATTRIBUTE_NAME_SUFFIX
);
}
public static String createIndexBackRefAttributeName(String pluralAttributeRole) {
return createSyntheticAttributeName(
pluralAttributeRole,
BACKREF_ATTRIBUTE_NAME_PREFIX,
INDEX_BACKREF_ATTRIBUTE_NAME_SUFFIX
);
}
private static String createSyntheticAttributeName(String attributeRole, String prefix, String suffix) {
return new StringBuilder(
prefix.length() + attributeRole.length() + suffix.length() )
.append( prefix )
.append( attributeRole )
.append( suffix )
.toString();
}
}

View File

@ -211,14 +211,14 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
// copy created before we actually copy
//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
super.cascadeBeforeSave( source, persister, entity, copyCache );
copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT );
copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.FROM_PARENT );
saveTransientEntity( copy, entityName, event.getRequestedId(), source, copyCache );
// cascade first, so that all unsaved objects get their
// copy created before we actually copy
super.cascadeAfterSave( source, persister, entity, copyCache );
copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_TO_PARENT );
copyValues( persister, entity, copy, source, copyCache, ForeignKeyDirection.TO_PARENT );
event.setResult( copy );
}
@ -391,7 +391,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme
final Object[] copiedValues;
if ( foreignKeyDirection == ForeignKeyDirection.FOREIGN_KEY_TO_PARENT ) {
if ( foreignKeyDirection == ForeignKeyDirection.TO_PARENT ) {
// this is the second pass through on a merge op, so here we limit the
// replacement to associations types (value types were already replaced
// during the first pass)

View File

@ -26,7 +26,7 @@ package org.hibernate.event.service.internal;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;

View File

@ -28,6 +28,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.Type;
@ -57,7 +58,7 @@ public class Assigned implements IdentifierGenerator, Configurable {
return id;
}
public void configure(Type type, Properties params, Dialect d) throws MappingException {
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) throws MappingException {
entityName = params.getProperty(ENTITY_NAME);
if ( entityName == null ) {
throw new MappingException("no entity name");

View File

@ -22,9 +22,9 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.id;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -102,7 +102,7 @@ public class CompositeNestedGeneratedValueGenerator implements IdentifierGenerat
}
private final GenerationContextLocator generationContextLocator;
private List generationPlans = new ArrayList();
private List<GenerationPlan> generationPlans = new ArrayList<GenerationPlan>();
public CompositeNestedGeneratedValueGenerator(GenerationContextLocator generationContextLocator) {
this.generationContextLocator = generationContextLocator;
@ -115,19 +115,15 @@ public class CompositeNestedGeneratedValueGenerator implements IdentifierGenerat
@Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
final Serializable context = generationContextLocator.locateGenerationContext( session, object );
for ( Object generationPlan : generationPlans ) {
final GenerationPlan plan = (GenerationPlan) generationPlan;
for ( final GenerationPlan plan : generationPlans ) {
plan.execute( session, object, context );
}
return context;
}
@Override
public void registerPersistentGenerators(Map generatorMap) {
for ( Object generationPlan : generationPlans ) {
final GenerationPlan plan = (GenerationPlan) generationPlan;
for(final GenerationPlan plan : generationPlans){
plan.registerPersistentGenerators( generatorMap );
}
}

View File

@ -26,6 +26,7 @@ package org.hibernate.id;
import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.type.Type;
@ -43,7 +44,8 @@ public interface Configurable {
* This method is called just once, following instantiation.
*
* @param params param values, keyed by parameter name
* @param classLoaderService
*/
public void configure(Type type, Properties params, Dialect d) throws MappingException;
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) throws MappingException;
}

View File

@ -0,0 +1,75 @@
/*
* 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.id;
/**
* Describes the nature of the entity-defined identifier.
*
* @author Steve Ebersole
*/
public enum EntityIdentifierNature {
/**
* A simple identifier. Resolved as a basic type and mapped to a singular, basic attribute. Equivalent of:<ul>
* <li>an {@code <id/>} mapping</li>
* <li>a single {@code @Id} annotation</li>
* </ul>
*/
SIMPLE,
/**
* What Hibernate used to term an "embedded composite identifier", which is not to be confused with the JPA
* term embedded. Resolved as a tuple of basic type values and mapped over multiple singular attributes.
* Specifically a composite identifier where there is no single attribute representing the composite value.
* Equivalent of:<ul>
* <li>
* a {@code <composite-id/>} mapping without a specified {@code name} XML-attribute (which would name
* the single identifier attribute
* </li>
* <li>
* multiple {@code @Id} annotations
* </li>
* </ul>
*
* NOTE : May or may not have a related "lookup identifier class" as indicated by a {@code @IdClass} annotation.
*
* @see javax.persistence.IdClass
*/
NON_AGGREGATED_COMPOSITE,
/**
* Composite identifier mapped to a single entity attribute by means of an actual component class used to
* aggregate the tuple values.
* Equivalent of:<ul>
* <li>
* a {@code <composite-id/>} mapping naming a single identifier attribute via the {@code name} XML-attribute
* </li>
* <li>
* an {@code @EmbeddedId} annotation
* </li>
* </ul>
*
* @see javax.persistence.EmbeddedId
*/
AGGREGATED_COMPOSITE
}

View File

@ -29,6 +29,7 @@ import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.Session;
import org.hibernate.TransientObjectException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.SessionImplementor;
@ -80,7 +81,7 @@ public class ForeignGenerator implements IdentifierGenerator, Configurable {
}
@Override
public void configure(Type type, Properties params, Dialect d) {
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) {
propertyName = params.getProperty( "property" );
entityName = params.getProperty( ENTITY_NAME );
if ( propertyName==null ) {

View File

@ -31,6 +31,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
@ -71,7 +72,7 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
return previousValueHolder.makeValueThenIncrement();
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) throws MappingException {
returnClass = type.getReturnedClass();
ObjectNameNormalizer normalizer =

View File

@ -34,6 +34,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.internal.FormatStyle;
@ -47,7 +48,12 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -99,7 +105,12 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
private static final String DEFAULT_PK_COLUMN = "sequence_name";
private static final String DEFAULT_VALUE_COLUMN = "sequence_next_hi_value";
private ObjectName qualifiedTableName;
private Identifier qualifiedPkColumnName;
private Identifier qualifiedValueColumnName;
private String tableName;
private Table table;
private String pkColumnName;
private String valueColumnName;
private String query;
@ -143,6 +154,15 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
return tableName;
}
/**
* The bound Table for this generator.
*
* @return The table.
*/
public final Table getTable() {
return table;
}
public synchronized Serializable generate(final SessionImplementor session, Object obj) {
final SqlStatementLogger statementLogger = session.getFactory().getServiceRegistry()
.getService( JdbcServices.class )
@ -268,35 +288,35 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
}
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) throws MappingException {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
tableName = normalizer.normalizeIdentifierQuoting( ConfigurationHelper.getString( ID_TABLE, params, DEFAULT_TABLE ) );
if ( tableName.indexOf( '.' ) < 0 ) {
tableName = dialect.quote( tableName );
final String schemaName = dialect.quote(
normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) )
);
final String catalogName = dialect.quote(
normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) )
);
tableName = Table.qualify( catalogName, schemaName, tableName );
final String normalizedTableName = tableName;
final String normalizedSchemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String normalizedCatalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
qualifiedTableName = new ObjectName( normalizedCatalogName, normalizedSchemaName, normalizedTableName );
tableName = qualifiedTableName.toText( dialect );
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
qualifiedTableName = ObjectName.parse( tableName );
}
pkColumnName = dialect.quote(
qualifiedPkColumnName = Identifier.toIdentifier(
normalizer.normalizeIdentifierQuoting(
ConfigurationHelper.getString( PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN )
)
);
valueColumnName = dialect.quote(
pkColumnName = qualifiedPkColumnName.getText( dialect );
qualifiedValueColumnName = Identifier.toIdentifier(
normalizer.normalizeIdentifierQuoting(
ConfigurationHelper.getString( VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN )
)
);
valueColumnName = qualifiedValueColumnName.getText( dialect );
keySize = ConfigurationHelper.getInt(PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH);
String keyValue = ConfigurationHelper.getString(PK_VALUE_NAME, params, params.getProperty(TABLE) );
@ -332,4 +352,20 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera
hiloOptimizer = new LegacyHiLoAlgorithmOptimizer( returnClass, maxLo );
}
}
@Override
public void registerExportables(Database database) {
final Dialect dialect = database.getJdbcEnvironment().getDialect();
final Schema schema = database.getSchemaFor( qualifiedTableName );
table = schema.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
final Column pkColumn = table.createColumn( qualifiedPkColumnName );
table.getPrimaryKey().addColumn( pkColumn );
// todo : leverage TypeInfo-like info from JdbcEnvironment
pkColumn.setSqlType( dialect.getTypeName( Types.VARCHAR, keySize, 0, 0 ) );
final Column valueColumn = table.createColumn( qualifiedValueColumnName );
valueColumn.setSqlType( dialect.getTypeName( Types.INTEGER ) );
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.id;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.spi.relational.ExportableProducer;
/**
* An <tt>IdentifierGenerator</tt> that requires creation of database objects.
@ -35,7 +36,7 @@ import org.hibernate.dialect.Dialect;
* @see Configurable
* @author Gavin King
*/
public interface PersistentIdentifierGenerator extends IdentifierGenerator {
public interface PersistentIdentifierGenerator extends IdentifierGenerator, ExportableProducer {
/**
* The configuration parameter holding the schema name

View File

@ -32,6 +32,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.insert.AbstractSelectingDelegate;
@ -52,7 +53,7 @@ public class SelectGenerator extends AbstractPostInsertGenerator implements Conf
private String uniqueKeyPropertyName;
public void configure(Type type, Properties params, Dialect d) throws MappingException {
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) throws MappingException {
uniqueKeyPropertyName = params.getProperty( "key" );
}

View File

@ -29,17 +29,20 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* <b>sequence</b><br>
* <br>
@ -50,12 +53,19 @@ import org.jboss.logging.Logger;
*
* @see SequenceHiLoGenerator
* @author Gavin King
*
* @deprecated Going away in 5.0, use {@link org.hibernate.id.enhanced.SequenceStyleGenerator} instead
*/
@Deprecated
public class SequenceGenerator
implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable {
private static final Logger LOG = Logger.getLogger( SequenceGenerator.class.getName() );
public SequenceGenerator() {
LOG.warn( "Encountered use of deprecated " + getClass().getName() + " class" );
}
/**
* The sequence parameter
*/
@ -67,6 +77,8 @@ public class SequenceGenerator
*/
public static final String PARAMETERS = "parameters";
private ObjectName qualifiedSequenceName;
private String sequenceName;
private String parameters;
private Type identifierType;
@ -85,29 +97,24 @@ public class SequenceGenerator
}
@Override
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) throws MappingException {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
sequenceName = normalizer.normalizeIdentifierQuoting(
ConfigurationHelper.getString( SEQUENCE, params, "hibernate_sequence" )
);
parameters = params.getProperty( PARAMETERS );
if ( sequenceName.indexOf( '.' ) < 0 ) {
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
sequenceName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( sequenceName )
);
sequenceName = new ObjectName( catalogName, schemaName, sequenceName ).toText( dialect );
this.qualifiedSequenceName = new ObjectName( catalogName, schemaName, sequenceName );
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
this.qualifiedSequenceName = ObjectName.parse( sequenceName );
}
this.parameters = params.getProperty( PARAMETERS );
this.identifierType = type;
sql = dialect.getSequenceNextValString( sequenceName );
this.sql = dialect.getSequenceNextValString( sequenceName );
}
@Override
@ -149,6 +156,14 @@ public class SequenceGenerator
return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() );
}
@Override
public void registerExportables(Database database) {
final Schema schema = database.getSchemaFor( qualifiedSequenceName );
if ( schema.locateSequence( qualifiedSequenceName.getName() ) == null ) {
schema.createSequence( qualifiedSequenceName.getName(), 1, 1 );
}
}
@Override
@SuppressWarnings( {"deprecation"})
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {

View File

@ -26,6 +26,7 @@ import java.io.Serializable;
import java.util.Properties;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.enhanced.AccessCallback;
@ -51,8 +52,8 @@ public class SequenceHiLoGenerator extends SequenceGenerator {
private LegacyHiLoAlgorithmOptimizer hiloOptimizer;
public void configure(Type type, Properties params, Dialect d) throws MappingException {
super.configure(type, params, d);
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) throws MappingException {
super.configure(type, params, d, classLoaderService );
maxLo = ConfigurationHelper.getInt( MAX_LO, params, 9 );

View File

@ -26,10 +26,10 @@ package org.hibernate.id;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.insert.AbstractReturningDelegate;
@ -37,9 +37,6 @@ import org.hibernate.id.insert.IdentifierGeneratingInsert;
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.sql.Insert;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* A generator which combines sequence generation with immediate retrieval
@ -75,11 +72,6 @@ public class SequenceIdentityGenerator
return new Delegate( persister, dialect, getSequenceName() );
}
@Override
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
super.configure( type, params, dialect );
}
public static class Delegate extends AbstractReturningDelegate {
private final Dialect dialect;
private final String sequenceNextValFragment;

View File

@ -33,6 +33,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.internal.FormatStyle;
@ -44,7 +45,8 @@ import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -73,8 +75,9 @@ import org.jboss.logging.Logger;
*
* @see TableHiLoGenerator
* @author Gavin King
*
* @deprecated use {@link SequenceStyleGenerator} instead.
*
* @deprecated Going away in 5.0, use {@link org.hibernate.id.enhanced.SequenceStyleGenerator} or
* {@link org.hibernate.id.enhanced.TableGenerator} instead
*/
@Deprecated
public class TableGenerator implements PersistentIdentifierGenerator, Configurable {
@ -99,7 +102,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
private String query;
private String update;
public void configure(Type type, Properties params, Dialect dialect) {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) {
identifierType = type;
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
@ -108,11 +111,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
if ( tableName.indexOf( '.' ) < 0 ) {
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
tableName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( tableName )
);
tableName = new ObjectName(catalogName, schemaName, tableName).toText( dialect );
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
@ -160,40 +159,50 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
// The loop ensures atomicity of the select + update even for no transaction or
// read committed isolation level
do {
final PreparedStatement qps = prepareStatement( connection, query, statementLogger, listeners );
final PreparedStatement qps = prepareStatement(
connection,
query,
statementLogger,
listeners
);
try {
ResultSet rs = executeQuery( qps, listeners );
if ( !rs.next() ) {
String err = "could not read a hi value - you need to populate the table: " + tableName;
LOG.error(err);
throw new IdentifierGenerationException(err);
LOG.error( err );
throw new IdentifierGenerationException( err );
}
value.initialize( rs, 1 );
rs.close();
}
catch (SQLException e) {
LOG.error("Could not read a hi value", e);
catch ( SQLException e ) {
LOG.error( "Could not read a hi value", e );
throw e;
}
finally {
qps.close();
}
final PreparedStatement ups = prepareStatement( connection, update, statementLogger, listeners );
final PreparedStatement ups = prepareStatement(
connection,
update,
statementLogger,
listeners
);
try {
value.copy().increment().bind( ups, 1 );
value.bind( ups, 2 );
rows = executeUpdate( ups, listeners );
}
catch (SQLException sqle) {
LOG.error(LOG.unableToUpdateHiValue(tableName), sqle);
catch ( SQLException sqle ) {
LOG.error( LOG.unableToUpdateHiValue( tableName ), sqle );
throw sqle;
}
finally {
ups.close();
}
}
while (rows==0);
while ( rows == 0 );
return value;
}
},
@ -237,6 +246,11 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
}
}
@Override
public void registerExportables(Database database) {
// not doing anything here as I expect this to go away
}
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
return new String[] {
dialect.getCreateTableString() + " " + tableName + " ( "

View File

@ -25,6 +25,7 @@ package org.hibernate.id;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.enhanced.AccessCallback;
@ -63,8 +64,8 @@ public class TableHiLoGenerator extends TableGenerator {
private int maxLo;
@Override
public void configure(Type type, Properties params, Dialect d) {
super.configure( type, params, d );
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) {
super.configure( type, params, d, classLoaderService );
maxLo = ConfigurationHelper.getInt( MAX_LO, params, Short.MAX_VALUE );
if ( maxLo >= 1 ) {

View File

@ -29,6 +29,8 @@ import java.util.UUID;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.uuid.StandardRandomStrategy;
@ -36,7 +38,6 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
import org.jboss.logging.Logger;
/**
@ -72,7 +73,7 @@ public class UUIDGenerator implements IdentifierGenerator, Configurable {
return generator;
}
public void configure(Type type, Properties params, Dialect d) throws MappingException {
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) throws MappingException {
// check first for the strategy instance
strategy = (UUIDGenerationStrategy) params.get( UUID_GEN_STRATEGY );
if ( strategy == null ) {
@ -80,7 +81,14 @@ public class UUIDGenerator implements IdentifierGenerator, Configurable {
final String strategyClassName = params.getProperty( UUID_GEN_STRATEGY_CLASS );
if ( strategyClassName != null ) {
try {
final Class strategyClass = ReflectHelper.classForName( strategyClassName );
final Class strategyClass;
// TODO: Exists purely for testing using the old .mappings. Eventually remove.
if (classLoaderService == null) {
strategyClass = ReflectHelper.classForName( strategyClassName );
}
else {
strategyClass = classLoaderService.classForName( strategyClassName );
}
try {
strategy = (UUIDGenerationStrategy) strategyClass.newInstance();
}
@ -88,9 +96,12 @@ public class UUIDGenerator implements IdentifierGenerator, Configurable {
LOG.unableToInstantiateUuidGenerationStrategy(ignore);
}
}
catch ( ClassNotFoundException ignore ) {
catch ( ClassLoadingException ignore ) {
LOG.unableToLocateUuidGenerationStrategy(strategyClassName);
}
catch ( ClassNotFoundException ignore ) {
LOG.unableToLocateUuidGenerationStrategy(strategyClassName);
}
}
}
if ( strategy == null ) {

View File

@ -26,6 +26,7 @@ package org.hibernate.id;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreMessageLogger;
@ -61,7 +62,7 @@ public class UUIDHexGenerator extends AbstractUUIDGenerator implements Configura
}
@Override
public void configure(Type type, Properties params, Dialect d) {
public void configure(Type type, Properties params, Dialect d, ClassLoaderService classLoaderService) {
sep = ConfigurationHelper.getString( "separator", params, "" );
}

View File

@ -25,6 +25,7 @@ package org.hibernate.id.enhanced;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.metamodel.spi.relational.ExportableProducer;
/**
* Encapsulates definition of the underlying data structure backing a
@ -32,7 +33,7 @@ import org.hibernate.engine.spi.SessionImplementor;
*
* @author Steve Ebersole
*/
public interface DatabaseStructure {
public interface DatabaseStructure extends ExportableProducer {
/**
* The name of the database structure (table or sequence).
* @return The structure name.

View File

@ -25,9 +25,8 @@ package org.hibernate.id.enhanced;
import java.lang.reflect.Constructor;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.jboss.logging.Logger;
/**
@ -61,13 +60,15 @@ public class OptimizerFactory {
* @param type The optimizer type, either a short-hand name or the {@link Optimizer} class name.
* @param returnClass The generated value java type
* @param incrementSize The increment size.
* @param classLoaderService ClassLoaderService
*
* @return The built optimizer
*
* @deprecated Use {@link #buildOptimizer(String, Class, int, long)} instead
*/
@Deprecated
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize) {
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize,
ClassLoaderService classLoaderService) {
final Class<? extends Optimizer> optimizerClass;
final StandardOptimizerDescriptor standardDescriptor = StandardOptimizerDescriptor.fromExternalName( type );
@ -76,7 +77,7 @@ public class OptimizerFactory {
}
else {
try {
optimizerClass = ReflectHelper.classForName( type );
optimizerClass = classLoaderService.classForName( type );
}
catch( Throwable ignore ) {
LOG.unableToLocateCustomOptimizerClass( type );
@ -106,11 +107,12 @@ public class OptimizerFactory {
* @param returnClass The generated value java type
* @param incrementSize The increment size.
* @param explicitInitialValue The user supplied initial-value (-1 indicates the user did not specify).
* @param classLoaderService ClassLoaderService
*
* @return The built optimizer
*/
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize, long explicitInitialValue) {
final Optimizer optimizer = buildOptimizer( type, returnClass, incrementSize );
public static Optimizer buildOptimizer(String type, Class returnClass, int incrementSize, long explicitInitialValue, ClassLoaderService classLoaderService) {
final Optimizer optimizer = buildOptimizer( type, returnClass, incrementSize, classLoaderService );
if ( InitialValueAwareOptimizer.class.isInstance( optimizer ) ) {
( (InitialValueAwareOptimizer) optimizer ).injectInitialValue( explicitInitialValue );
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* Copyright (c) 2008, 2012, 2013, 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.
@ -22,19 +22,22 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.id.enhanced;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Sequence;
/**
* Describes a sequence.
@ -47,6 +50,7 @@ public class SequenceStructure implements DatabaseStructure {
SequenceStructure.class.getName()
);
private ObjectName qualifiedSequenceName;
private final String sequenceName;
private final int initialValue;
private final int incrementSize;
@ -57,11 +61,12 @@ public class SequenceStructure implements DatabaseStructure {
public SequenceStructure(
Dialect dialect,
String sequenceName,
ObjectName qualifiedSequenceName,
int initialValue,
int incrementSize,
Class numberType) {
this.sequenceName = sequenceName;
this.qualifiedSequenceName = qualifiedSequenceName;
this.sequenceName = qualifiedSequenceName.toText( dialect );
this.initialValue = initialValue;
this.incrementSize = incrementSize;
this.numberType = numberType;
@ -142,6 +147,19 @@ public class SequenceStructure implements DatabaseStructure {
applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues();
}
@Override
public void registerExportables(Database database) {
final int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1;
final Schema schema = database.getSchemaFor( qualifiedSequenceName );
Sequence sequence = schema.locateSequence( qualifiedSequenceName.getName() );
if ( sequence != null ) {
sequence.validate( initialValue, sourceIncrementSize );
}
else {
schema.createSequence( qualifiedSequenceName.getName(), initialValue, sourceIncrementSize );
}
}
@Override
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
final int sourceIncrementSize = applyIncrementSizeToSourceValues ? incrementSize : 1;

View File

@ -26,8 +26,11 @@ package org.hibernate.id.enhanced;
import java.io.Serializable;
import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
@ -37,11 +40,11 @@ import org.hibernate.id.Configurable;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
* Generates identifier values based on an sequence-style database structure.
* Variations range from actually using a sequence to using a table to mimic
@ -227,11 +230,12 @@ public class SequenceStyleGenerator
// Configurable implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) throws MappingException {
this.identifierType = type;
boolean forceTableUse = ConfigurationHelper.getBoolean( FORCE_TBL_PARAM, params, false );
final String sequenceName = determineSequenceName( params, dialect );
final ObjectName qualifiedSequenceName = determineSequenceName( params, dialect );
final String sequenceNameText = qualifiedSequenceName.toText( dialect );
final int initialValue = determineInitialValue( params );
int incrementSize = determineIncrementSize( params );
@ -251,7 +255,7 @@ public class SequenceStyleGenerator
params,
dialect,
forceTableUse,
sequenceName,
qualifiedSequenceName,
initialValue,
incrementSize
);
@ -259,7 +263,8 @@ public class SequenceStyleGenerator
optimizationStrategy,
identifierType.getReturnedClass(),
incrementSize,
ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 )
ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 ),
classLoaderService
);
this.databaseStructure.prepare( optimizer );
}
@ -274,28 +279,25 @@ public class SequenceStyleGenerator
* @param dialect The dialect in effect
* @return The sequence name
*/
protected String determineSequenceName(Properties params, Dialect dialect) {
final String sequencePerEntitySuffix = ConfigurationHelper.getString( CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX );
protected ObjectName determineSequenceName(Properties params, Dialect dialect) {
String sequencePerEntitySuffix = ConfigurationHelper.getString( CONFIG_SEQUENCE_PER_ENTITY_SUFFIX, params, DEF_SEQUENCE_SUFFIX );
// JPA_ENTITY_NAME value honors <class ... entity-name="..."> (HBM) and @Entity#name (JPA) overrides.
String sequenceName = ConfigurationHelper.getBoolean( CONFIG_PREFER_SEQUENCE_PER_ENTITY, params, false )
? params.getProperty( JPA_ENTITY_NAME ) + sequencePerEntitySuffix
: DEF_SEQUENCE_NAME;
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
sequenceName = ConfigurationHelper.getString( SEQUENCE_PARAM, params, sequenceName );
final ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
sequenceName = normalizer.normalizeIdentifierQuoting(
ConfigurationHelper.getString( SEQUENCE_PARAM, params, sequenceName )
);
if ( sequenceName.indexOf( '.' ) < 0 ) {
sequenceName = normalizer.normalizeIdentifierQuoting( sequenceName );
final String schemaName = params.getProperty( SCHEMA );
final String catalogName = params.getProperty( CATALOG );
sequenceName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( sequenceName )
);
}
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
return sequenceName;
return new ObjectName( catalogName, schemaName, sequenceName );
}
else {
return ObjectName.parse( sequenceName );
}
}
/**
@ -309,10 +311,10 @@ public class SequenceStyleGenerator
* @param dialect The dialect in effect.
* @return The value column name
*/
protected String determineValueColumnName(Properties params, Dialect dialect) {
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
protected Identifier determineValueColumnName(Properties params, Dialect dialect) {
final ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
final String name = ConfigurationHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
return Identifier.toIdentifier( normalizer.normalizeIdentifierQuoting( name ) );
}
/**
@ -401,7 +403,7 @@ public class SequenceStyleGenerator
Properties params,
Dialect dialect,
boolean forceTableUse,
String sequenceName,
ObjectName sequenceName,
int initialValue,
int incrementSize) {
final boolean useSequence = dialect.supportsSequences() && !forceTableUse;
@ -409,7 +411,7 @@ public class SequenceStyleGenerator
return new SequenceStructure( dialect, sequenceName, initialValue, incrementSize, type.getReturnedClass() );
}
else {
final String valueColumnName = determineValueColumnName( params, dialect );
Identifier valueColumnName = determineValueColumnName( params, dialect );
return new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize, type.getReturnedClass() );
}
}
@ -430,6 +432,11 @@ public class SequenceStyleGenerator
return databaseStructure.getName();
}
@Override
public void registerExportables(Database database) {
databaseStructure.registerExportables( database );
}
@Override
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
return databaseStructure.sqlCreateStrings( dialect );

View File

@ -37,6 +37,7 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
@ -53,7 +54,11 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -226,7 +231,12 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
private Type identifierType;
private ObjectName qualifiedTableName;
private Identifier qualifiedSegmentColumnName;
private Identifier qualifiedValueColumnName;
private String tableName;
private Table table;
private String segmentColumnName;
private String segmentValue;
@ -266,6 +276,15 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
return tableName;
}
/**
* The bound Table for this generator.
*
* @return The table.
*/
public final Table getTable() {
return table;
}
/**
* The name of the column in which we store the segment to which each row
* belongs. The value here acts as PK.
@ -349,7 +368,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
}
@Override
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
public void configure(Type type, Properties params, Dialect dialect, ClassLoaderService classLoaderService) throws MappingException {
identifierType = type;
tableName = determineGeneratorTableName( params, dialect );
@ -379,14 +398,15 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
optimizationStrategy,
identifierType.getReturnedClass(),
incrementSize,
ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 )
ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 ),
classLoaderService
);
}
/**
* Determine the table name to use for the generator values.
* <p/>
* Called during {@link #configure configuration}.
* Called during {@link org.hibernate.id.Configurable#configure configuration}.
*
* @see #getTableName()
* @param params The params supplied in the generator config (plus some standard useful extras).
@ -394,22 +414,23 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
* @return The table name to use.
*/
protected String determineGeneratorTableName(Properties params, Dialect dialect) {
String name = ConfigurationHelper.getString( TABLE_PARAM, params, DEF_TABLE );
final ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
String name = normalizer.normalizeIdentifierQuoting(
ConfigurationHelper.getString( TABLE_PARAM, params, DEF_TABLE )
);
final boolean isGivenNameUnqualified = name.indexOf( '.' ) < 0;
if ( isGivenNameUnqualified ) {
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
name = normalizer.normalizeIdentifierQuoting( name );
// if the given name is un-qualified we may neen to qualify it
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
name = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( name)
);
qualifiedTableName = new ObjectName( catalogName, schemaName, name );
name = qualifiedTableName.toText( dialect );
}
else {
qualifiedTableName = ObjectName.parse( name );
}
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
return name;
}
@ -418,7 +439,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
* Determine the name of the column used to indicate the segment for each
* row. This column acts as the primary key.
* <p/>
* Called during {@link #configure configuration}.
* Called during {@link org.hibernate.id.Configurable#configure configuration}.
*
* @see #getSegmentColumnName()
* @param params The params supplied in the generator config (plus some standard useful extras).
@ -428,13 +449,14 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
protected String determineSegmentColumnName(Properties params, Dialect dialect) {
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
final String name = ConfigurationHelper.getString( SEGMENT_COLUMN_PARAM, params, DEF_SEGMENT_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
qualifiedSegmentColumnName = Identifier.toIdentifier( normalizer.normalizeIdentifierQuoting( name ) );
return qualifiedSegmentColumnName.getText( dialect );
}
/**
* Determine the name of the column in which we will store the generator persistent value.
* <p/>
* Called during {@link #configure configuration}.
* Called during {@link org.hibernate.id.Configurable#configure configuration}.
*
* @see #getValueColumnName()
* @param params The params supplied in the generator config (plus some standard useful extras).
@ -444,13 +466,14 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
protected String determineValueColumnName(Properties params, Dialect dialect) {
final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( IDENTIFIER_NORMALIZER );
final String name = ConfigurationHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
qualifiedValueColumnName = Identifier.toIdentifier( normalizer.normalizeIdentifierQuoting( name ) );
return qualifiedValueColumnName.getText( dialect );
}
/**
* Determine the segment value corresponding to this generator instance.
* <p/>
* Called during {@link #configure configuration}.
* Called during {@link org.hibernate.id.Configurable#configure configuration}.
*
* @see #getSegmentValue()
* @param params The params supplied in the generator config (plus some standard useful extras).
@ -472,16 +495,20 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
* @return The default segment value to use.
*/
protected String determineDefaultSegmentValue(Properties params) {
final boolean preferSegmentPerEntity = ConfigurationHelper.getBoolean( CONFIG_PREFER_SEGMENT_PER_ENTITY, params, false );
final boolean preferSegmentPerEntity = ConfigurationHelper.getBoolean(
CONFIG_PREFER_SEGMENT_PER_ENTITY,
params,
false
);
final String defaultToUse = preferSegmentPerEntity ? params.getProperty( TABLE ) : DEF_SEGMENT_VALUE;
LOG.usingDefaultIdGeneratorSegmentValue( tableName, segmentColumnName, defaultToUse );
LOG.usingDefaultIdGeneratorSegmentValue( qualifiedTableName.toString(), segmentColumnName, defaultToUse );
return defaultToUse;
}
/**
* Determine the size of the {@link #getSegmentColumnName segment column}
* <p/>
* Called during {@link #configure configuration}.
* Called during {@link org.hibernate.id.Configurable#configure configuration}.
*
* @see #getSegmentValueLength()
* @param params The params supplied in the generator config (plus some standard useful extras).
@ -502,7 +529,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
protected String buildSelectQuery(Dialect dialect) {
final String alias = "tbl";
final String query = "select " + StringHelper.qualify( alias, valueColumnName ) +
" from " + tableName + ' ' + alias +
" from " + qualifiedTableName.toText( dialect ) + ' ' + alias +
" where " + StringHelper.qualify( alias, segmentColumnName ) + "=?";
final LockOptions lockOptions = new LockOptions( LockMode.PESSIMISTIC_WRITE );
lockOptions.setAliasSpecificLockMode( alias, LockMode.PESSIMISTIC_WRITE );
@ -511,7 +538,7 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
}
protected String buildUpdateQuery() {
return "update " + tableName +
return "update " + qualifiedTableName.toText( ) +
" set " + valueColumnName + "=? " +
" where " + valueColumnName + "=? and " + segmentColumnName + "=?";
}
@ -535,76 +562,98 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
new AccessCallback() {
@Override
public IntegralDataTypeHolder getNextValue() {
return session.getTransactionCoordinator().getTransaction().createIsolationDelegate().delegateWork(
new AbstractReturningWork<IntegralDataTypeHolder>() {
@Override
public IntegralDataTypeHolder execute(Connection connection) throws SQLException {
final IntegralDataTypeHolder value = makeValue();
int rows;
do {
final PreparedStatement selectPS = prepareStatement( connection, selectQuery, statementLogger, statsCollector );
return session.getTransactionCoordinator()
.getTransaction()
.createIsolationDelegate()
.delegateWork(
new AbstractReturningWork<IntegralDataTypeHolder>() {
@Override
public IntegralDataTypeHolder execute(Connection connection)
throws SQLException {
final IntegralDataTypeHolder value = makeValue();
int rows;
do {
final PreparedStatement selectPS = prepareStatement(
connection,
selectQuery,
statementLogger,
statsCollector
);
try {
selectPS.setString( 1, segmentValue );
final ResultSet selectRS = executeQuery( selectPS, statsCollector );
if ( !selectRS.next() ) {
value.initialize( initialValue );
final PreparedStatement insertPS = prepareStatement( connection, insertQuery, statementLogger, statsCollector );
try {
insertPS.setString( 1, segmentValue );
value.bind( insertPS, 2 );
executeUpdate( insertPS, statsCollector );
selectPS.setString( 1, segmentValue );
final ResultSet selectRS = executeQuery(
selectPS,
statsCollector
);
if ( !selectRS.next() ) {
value.initialize( initialValue );
final PreparedStatement insertPS = prepareStatement(
connection,
insertQuery,
statementLogger,
statsCollector
);
try {
insertPS.setString( 1, segmentValue );
value.bind( insertPS, 2 );
executeUpdate( insertPS, statsCollector );
}
finally {
insertPS.close();
}
}
else {
value.initialize( selectRS, 1 );
}
selectRS.close();
}
catch ( SQLException e ) {
LOG.unableToReadOrInitHiValue( e );
throw e;
}
finally {
insertPS.close();
selectPS.close();
}
final PreparedStatement updatePS = prepareStatement(
connection,
updateQuery,
statementLogger,
statsCollector
);
try {
final IntegralDataTypeHolder updateValue = value.copy();
if ( optimizer.applyIncrementSizeToSourceValues() ) {
updateValue.add( incrementSize );
}
else {
updateValue.increment();
}
updateValue.bind( updatePS, 1 );
value.bind( updatePS, 2 );
updatePS.setString( 3, segmentValue );
rows = executeUpdate( updatePS, statsCollector );
}
catch ( SQLException e ) {
LOG.unableToUpdateQueryHiValue( tableName, e );
throw e;
}
finally {
updatePS.close();
}
}
else {
value.initialize( selectRS, 1 );
}
selectRS.close();
}
catch (SQLException e) {
LOG.unableToReadOrInitHiValue( e );
throw e;
}
finally {
selectPS.close();
}
while ( rows == 0 );
accessCount++;
final PreparedStatement updatePS = prepareStatement( connection, updateQuery, statementLogger, statsCollector );
try {
final IntegralDataTypeHolder updateValue = value.copy();
if ( optimizer.applyIncrementSizeToSourceValues() ) {
updateValue.add( incrementSize );
}
else {
updateValue.increment();
}
updateValue.bind( updatePS, 1 );
value.bind( updatePS, 2 );
updatePS.setString( 3, segmentValue );
rows = executeUpdate( updatePS, statsCollector );
return value;
}
catch (SQLException e) {
LOG.unableToUpdateQueryHiValue( tableName, e );
throw e;
}
finally {
updatePS.close();
}
}
while ( rows == 0 );
accessCount++;
return value;
}
},
true
);
},
true
);
}
@Override
@ -651,6 +700,24 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab
}
}
@Override
public void registerExportables(Database database) {
final Dialect dialect = database.getJdbcEnvironment().getDialect();
table = database.getSchemaFor( qualifiedTableName )
.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
Column segmentColumn = table.createColumn( qualifiedSegmentColumnName );
table.getPrimaryKey().addColumn( segmentColumn );
// todo : leverage TypeInfo-like info from JdbcEnvironment
segmentColumn.setSqlType( dialect.getTypeName( Types.VARCHAR, segmentValueLength, 0, 0 ) );
segmentColumn.setNullable( false );
Column valueColumn = table.createColumn( qualifiedValueColumnName );
valueColumn.setSqlType( dialect.getTypeName( Types.BIGINT ) );
valueColumn.setNullable( false );
}
@Override
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
return new String[] {

View File

@ -42,6 +42,13 @@ import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.InitCommand;
import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Table;
import org.jboss.logging.Logger;
@ -56,8 +63,10 @@ public class TableStructure implements DatabaseStructure {
TableStructure.class.getName()
);
private final ObjectName qualifiedTableName;
private final Identifier valueColumnName;
private final String tableName;
private final String valueColumnName;
private final int initialValue;
private final int incrementSize;
private final Class numberType;
@ -69,24 +78,27 @@ public class TableStructure implements DatabaseStructure {
public TableStructure(
Dialect dialect,
String tableName,
String valueColumnName,
ObjectName qualifiedTableName,
Identifier valueColumnName,
int initialValue,
int incrementSize,
Class numberType) {
this.tableName = tableName;
this.qualifiedTableName = qualifiedTableName;
this.valueColumnName = valueColumnName;
this.tableName = qualifiedTableName.toText( dialect );
this.initialValue = initialValue;
this.incrementSize = incrementSize;
this.valueColumnName = valueColumnName;
this.numberType = numberType;
selectQuery = "select " + valueColumnName + " as id_val" +
String valueColumnNameText = valueColumnName.getText( dialect );
selectQuery = "select " + valueColumnNameText + " as id_val" +
" from " + dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) +
dialect.getForUpdateString();
updateQuery = "update " + tableName +
" set " + valueColumnName + "= ?" +
" where " + valueColumnName + "=?";
" set " + valueColumnNameText + "= ?" +
" where " + valueColumnNameText + "=?";
}
@Override
@ -224,6 +236,25 @@ public class TableStructure implements DatabaseStructure {
}
}
@Override
public void registerExportables(Database database) {
final Dialect dialect = database.getJdbcEnvironment().getDialect();
final Schema schema = database.getSchemaFor( qualifiedTableName );
Table table = schema.locateTable( qualifiedTableName.getName() );
if ( table != null ) {
return;
}
table = schema.createTable( qualifiedTableName.getName(), qualifiedTableName.getName() );
Column valueColumn = table.createColumn( valueColumnName );
valueColumn.setSqlType( dialect.getTypeName( Types.BIGINT ) );
database.addInitCommand(
new InitCommand( "insert into " + tableName + " values ( " + initialValue + " )" )
);
}
@Override
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
return new String[] {

View File

@ -28,6 +28,8 @@ import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.id.Assigned;
@ -52,7 +54,6 @@ import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/**
@ -66,6 +67,7 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
DefaultIdentifierGeneratorFactory.class.getName());
private transient Dialect dialect;
private transient ClassLoaderService classLoaderService;
private ConcurrentHashMap<String, Class> generatorStrategyToClassNameMap = new ConcurrentHashMap<String, Class>();
/**
@ -88,7 +90,7 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
register( "enhanced-sequence", SequenceStyleGenerator.class );
register( "enhanced-table", TableGenerator.class );
}
@Override
public void register(String strategy, Class generatorClass) {
LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );
final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );
@ -114,7 +116,7 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
Class clazz = getIdentifierGeneratorClass( strategy );
IdentifierGenerator identifierGenerator = ( IdentifierGenerator ) clazz.newInstance();
if ( identifierGenerator instanceof Configurable ) {
( ( Configurable ) identifierGenerator ).configure( type, config, dialect );
( ( Configurable ) identifierGenerator ).configure( type, config, dialect, classLoaderService );
}
return identifierGenerator;
}
@ -133,9 +135,19 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
Class generatorClass = generatorStrategyToClassNameMap.get( strategy );
try {
if ( generatorClass == null ) {
generatorClass = ReflectHelper.classForName( strategy );
// TODO: Exists purely for testing using the old .mappings. Eventually remove.
if (classLoaderService == null) {
generatorClass = ReflectHelper.classForName( strategy );
}
else {
generatorClass = classLoaderService.classForName( strategy );
}
register( strategy, generatorClass );
}
}
catch ( ClassLoadingException e ) {
throw new MappingException( String.format( "Could not interpret id generator strategy [%s]", strategy ) );
}
catch ( ClassNotFoundException e ) {
throw new MappingException( String.format( "Could not interpret id generator strategy [%s]", strategy ) );
}
@ -145,5 +157,6 @@ public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGener
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.dialect = serviceRegistry.getService( JdbcServices.class ).getDialect();
this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
}
}

View File

@ -25,7 +25,7 @@ package org.hibernate.integrator.spi;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
/**

View File

@ -1674,4 +1674,46 @@ public interface CoreMessageLogger extends BasicLogger {
"(%2$s=true)"
)
void applyingExplicitDiscriminatorColumnForJoined(String className, String overrideSetting);
@Message(value = "@CollectionTable and @JoinTable specified on the same attribute. Check %s#%s", id = 458)
String collectionTableAndJoinTableUsedTogether(String entityName, String propertyName);
@Message(value = "@CollectionTable annotation without a @ElementCollection. Check %s#%s", id = 459)
String collectionTableWithoutElementCollection(String entityName, String propertyName);
@Message(value = "@JoinTable annotation without an association. Check %s#%s", id = 460)
String joinTableForNonAssociationAttribute(String entityName, String propertyName);
@LogMessage( level = ERROR )
@Message( value = "Illegal argument on static metamodel field injection : %s#%s; expected type : %s; encountered type : %s", id = 461 )
void illegalArgumentOnStaticMetamodelFieldInjection( String metamodelClassName,
String attributeName,
String attributeJavaType,
String metamodelFieldJavaType );
// moved from EntityManagerMessageLogger w/ id 15007
@LogMessage( level = ERROR )
@Message( value = "Unable to locate static metamodel field : %s#%s", id = 462 )
void unableToLocateStaticMetamodelField( String metamodelClassName,
String attributeName );
// moved from EntityManagerMessageLogger w/ id 15011
@Message(value = "The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter)", id = 463)
String accessTypeOverrideShouldBeAnnotatedOnProperty( String className );
@Message(value = "The access type of class %s is AccessType.FIELD. To override the access for an attribute " +
"@Access has to be placed on the property (getter) with an access type of AccessType.PROPERTY. " +
"Using AccessType.FIELD on the property has no effect", id = 464)
String accessTypeOverrideShouldBeProperty( String className );
@Message(value = "The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field ", id = 465)
String accessTypeOverrideShouldBeAnnotatedOnField( String className );
@Message(value = "The access type of class %s is AccessType.PROPERTY. To override the access for a field " +
"@Access has to be placed on the field with an access type of AccessType.FIELD. " +
"Using AccessType.PROPERTY on the field has no effect", id = 466)
String accessTypeOverrideShouldBeField( String className );
}

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.internal;
import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.Session;
import org.hibernate.persister.entity.EntityPersister;
/**
* The default implementation of {@link CustomEntityDirtinessStrategy} which does nada.
*
* @author Steve Ebersole
*/
public class DefaultCustomEntityDirtinessStrategy implements CustomEntityDirtinessStrategy {
public static final DefaultCustomEntityDirtinessStrategy INSTANCE = new DefaultCustomEntityDirtinessStrategy();
@Override
public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) {
return false;
}
@Override
public boolean isDirty(Object entity, EntityPersister persister, Session session) {
return false;
}
@Override
public void resetDirty(Object entity, EntityPersister persister, Session session) {
}
@Override
public void findDirty(
Object entity,
EntityPersister persister,
Session session,
DirtyCheckContext dirtyCheckContext) {
}
}

View File

@ -29,9 +29,11 @@ import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.persister.entity.Joinable;
/**
* Captures all relevant metadata specified as part of defining the filter.
*
* @author Rob Worsnop
*/
@ -42,14 +44,52 @@ public class FilterConfiguration {
private final Map<String, String> aliasTableMap;
private final Map<String, String> aliasEntityMap;
private final PersistentClass persistentClass;
public FilterConfiguration(String name, String condition, boolean autoAliasInjection, Map<String, String> aliasTableMap, Map<String, String> aliasEntityMap, PersistentClass persistentClass) {
private final EntityBinding entityBinding;
public FilterConfiguration(
String name,
String condition,
boolean autoAliasInjection,
Map<String, String> aliasTableMap,
Map<String, String> aliasEntityMap){
this.name = name;
this.condition = condition;
this.autoAliasInjection = autoAliasInjection;
this.aliasTableMap = aliasTableMap;
this.aliasEntityMap = aliasEntityMap;
this.entityBinding = null;
this.persistentClass = null;
}
public FilterConfiguration(
String name,
String condition,
boolean autoAliasInjection,
Map<String, String> aliasTableMap,
Map<String, String> aliasEntityMap,
PersistentClass persistentClass) {
this.name = name;
this.condition = condition;
this.autoAliasInjection = autoAliasInjection;
this.aliasTableMap = aliasTableMap;
this.aliasEntityMap = aliasEntityMap;
this.persistentClass = persistentClass;
this.entityBinding = null;
}
public FilterConfiguration(
String name,
String condition,
boolean autoAliasInjection,
Map<String, String> aliasTableMap,
Map<String, String> aliasEntityMap,
EntityBinding entityBinding) {
this.name = name;
this.condition = condition;
this.autoAliasInjection = autoAliasInjection;
this.aliasTableMap = aliasTableMap;
this.aliasEntityMap = aliasEntityMap;
this.persistentClass = null;
this.entityBinding = entityBinding;
}
public String getName() {
@ -65,28 +105,38 @@ public class FilterConfiguration {
}
public Map<String, String> getAliasTableMap(SessionFactoryImplementor factory) {
Map<String,String> mergedAliasTableMap = mergeAliasMaps(factory);
if (!mergedAliasTableMap.isEmpty()){
Map<String, String> mergedAliasTableMap = mergeAliasMaps( factory );
if ( !mergedAliasTableMap.isEmpty() ) {
return mergedAliasTableMap;
} else if (persistentClass != null){
String table = persistentClass.getTable().getQualifiedName(factory.getDialect(),
}
else if ( persistentClass != null ) {
String table = persistentClass.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName());
return Collections.singletonMap(null, table);
} else{
factory.getSettings().getDefaultSchemaName()
);
return Collections.singletonMap( null, table );
}
else if ( entityBinding != null ) {
String table = entityBinding.getPrimaryTable().getQualifiedName( factory.getDialect() );
return Collections.singletonMap( null, table );
}
else {
return Collections.emptyMap();
}
}
private Map<String,String> mergeAliasMaps(SessionFactoryImplementor factory){
Map<String,String> ret = new HashMap<String, String>();
if (aliasTableMap != null){
ret.putAll(aliasTableMap);
private Map<String, String> mergeAliasMaps(SessionFactoryImplementor factory) {
Map<String, String> ret = new HashMap<String, String>();
if ( aliasTableMap != null ) {
ret.putAll( aliasTableMap );
}
if (aliasEntityMap != null){
for (Map.Entry<String, String> entry : aliasEntityMap.entrySet()){
ret.put(entry.getKey(),
Joinable.class.cast(factory.getEntityPersister(entry.getValue())).getTableName());
if ( aliasEntityMap != null ) {
for ( Map.Entry<String, String> entry : aliasEntityMap.entrySet() ) {
ret.put(
entry.getKey(),
Joinable.class.cast( factory.getEntityPersister( entry.getValue() ) ).getTableName()
);
}
}
return ret;

View File

@ -43,6 +43,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.persistence.metamodel.Metamodel;
import org.hibernate.AssertionFailure;
import org.hibernate.Cache;
@ -66,6 +67,7 @@ import org.hibernate.TypeHelper;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
@ -83,7 +85,6 @@ import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings;
import org.hibernate.cfg.SettingsFactory;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.context.internal.ManagedSessionContext;
@ -125,14 +126,16 @@ import org.hibernate.id.UUIDGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.jpa.metamodel.internal.JpaMetaModelPopulationSetting;
import org.hibernate.jpa.metamodel.internal.builder.MetamodelBuilder;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
@ -216,20 +219,53 @@ public final class SessionFactoryImpl
private final transient TypeHelper typeHelper;
private final transient TransactionEnvironment transactionEnvironment;
private final transient SessionFactoryOptions sessionFactoryOptions;
private final transient CustomEntityDirtinessStrategy customEntityDirtinessStrategy;
private final transient CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
private final transient Metamodel jpaMetamodel;
@SuppressWarnings( {"unchecked", "ThrowableResultOfMethodCallIgnored"})
public SessionFactoryImpl(
final Configuration cfg,
Mapping mapping,
final ServiceRegistry serviceRegistry,
Settings settings,
SessionFactoryObserver observer) throws HibernateException {
final Settings settings,
final SessionFactoryObserver userObserver) throws HibernateException {
LOG.debug( "Building session factory" );
sessionFactoryOptions = new SessionFactoryOptions() {
private EntityNotFoundDelegate entityNotFoundDelegate;
private final Interceptor interceptor;
private final CustomEntityDirtinessStrategy customEntityDirtinessStrategy;
private final CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
private final EntityNotFoundDelegate entityNotFoundDelegate;
{
interceptor = cfg.getInterceptor();
customEntityDirtinessStrategy = serviceRegistry.getService( StrategySelector.class ).resolveDefaultableStrategy(
CustomEntityDirtinessStrategy.class,
cfg.getProperties().get( AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY ),
DefaultCustomEntityDirtinessStrategy.INSTANCE
);
if ( cfg.getCurrentTenantIdentifierResolver() != null ) {
currentTenantIdentifierResolver = cfg.getCurrentTenantIdentifierResolver();
}
else {
currentTenantIdentifierResolver =serviceRegistry.getService( StrategySelector.class ).resolveStrategy(
CurrentTenantIdentifierResolver.class,
cfg.getProperties().get( AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER )
);
}
if ( cfg.getEntityNotFoundDelegate() != null ) {
entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();
}
else {
entityNotFoundDelegate = new EntityNotFoundDelegate() {
public void handleEntityNotFound(String entityName, Serializable id) {
throw new ObjectNotFoundException( id, entityName );
}
};
}
}
@Override
public StandardServiceRegistry getServiceRegistry() {
@ -238,22 +274,39 @@ public final class SessionFactoryImpl
@Override
public Interceptor getInterceptor() {
return cfg.getInterceptor();
return interceptor;
}
@Override
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy() {
return customEntityDirtinessStrategy;
}
@Override
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() {
return currentTenantIdentifierResolver;
}
@Override
public SessionFactoryObserver[] getSessionFactoryObservers() {
return userObserver == null
? new SessionFactoryObserver[0]
: new SessionFactoryObserver[] { userObserver };
}
@Override
public EntityNameResolver[] getEntityNameResolvers() {
return new EntityNameResolver[0];
}
@Override
public Settings getSettings() {
return settings;
}
@Override
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
if ( entityNotFoundDelegate == null ) {
if ( cfg.getEntityNotFoundDelegate() != null ) {
entityNotFoundDelegate = cfg.getEntityNotFoundDelegate();
}
else {
entityNotFoundDelegate = new EntityNotFoundDelegate() {
public void handleEntityNotFound(String entityName, Serializable id) {
throw new ObjectNotFoundException( id, entityName );
}
};
}
}
return entityNotFoundDelegate;
}
@ -272,7 +325,7 @@ public final class SessionFactoryImpl
this.dialect = this.jdbcServices.getDialect();
this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class );
this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() );
if ( observer != null ) {
for ( SessionFactoryObserver observer : sessionFactoryOptions.getSessionFactoryObservers() ) {
this.observer.addObserver( observer );
}
@ -481,6 +534,12 @@ public final class SessionFactoryImpl
persister.postInstantiate();
registerEntityNameResolvers( persister );
}
if ( sessionFactoryOptions.getEntityNameResolvers() != null ) {
for ( EntityNameResolver resolver : sessionFactoryOptions.getEntityNameResolvers() ) {
registerEntityNameResolver( resolver );
}
}
for ( CollectionPersister persister : collectionPersisters.values() ) {
persister.postInstantiate();
}
@ -582,10 +641,20 @@ public final class SessionFactoryImpl
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
}
this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy();
this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( cfg.getCurrentTenantIdentifierResolver() );
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
this.observer.sessionFactoryCreated( this );
final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting = determineJpaMetaModelPopulationSetting( cfg );
if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.DISABLED ) {
this.jpaMetamodel = org.hibernate.jpa.metamodel.internal.legacy.MetamodelImpl.buildMetamodel(
cfg.getClassMappings(),
this,
jpaMetaModelPopulationSetting == JpaMetaModelPopulationSetting.IGNORE_UNSUPPORTED
);
}
else {
jpaMetamodel = null;
}
}
private Map<String, ProcedureCallMemento> toProcedureCallMementos(
@ -626,59 +695,16 @@ public final class SessionFactoryImpl
};
}
@SuppressWarnings({ "unchecked" })
private CustomEntityDirtinessStrategy determineCustomEntityDirtinessStrategy() {
CustomEntityDirtinessStrategy defaultValue = new CustomEntityDirtinessStrategy() {
@Override
public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) {
return false;
}
@Override
public boolean isDirty(Object entity, EntityPersister persister, Session session) {
return false;
}
@Override
public void resetDirty(Object entity, EntityPersister persister, Session session) {
}
@Override
public void findDirty(
Object entity,
EntityPersister persister,
Session session,
DirtyCheckContext dirtyCheckContext) {
// todo : implement proper method body
}
};
return serviceRegistry.getService( ConfigurationService.class ).getSetting(
AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY,
CustomEntityDirtinessStrategy.class,
defaultValue
);
}
@SuppressWarnings({ "unchecked" })
private CurrentTenantIdentifierResolver determineCurrentTenantIdentifierResolver(
CurrentTenantIdentifierResolver explicitResolver) {
if ( explicitResolver != null ) {
return explicitResolver;
}
return serviceRegistry.getService( ConfigurationService.class )
.getSetting(
AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER,
CurrentTenantIdentifierResolver.class,
null
);
protected JpaMetaModelPopulationSetting determineJpaMetaModelPopulationSetting(Configuration cfg) {
final String setting = cfg.getProperties().getProperty( AvailableSettings.JPA_METAMODEL_POPULATION );
return JpaMetaModelPopulationSetting.parse( setting );
}
@SuppressWarnings( {"ThrowableResultOfMethodCallIgnored"})
public SessionFactoryImpl(
MetadataImplementor metadata,
SessionFactoryOptions sessionFactoryOptions,
SessionFactoryObserver observer) throws HibernateException {
SessionFactoryOptions providedSessionFactoryOptions) throws HibernateException {
final boolean traceEnabled = LOG.isTraceEnabled();
final boolean debugEnabled = traceEnabled || LOG.isDebugEnabled();
@ -686,17 +712,13 @@ public final class SessionFactoryImpl
LOG.debug( "Building session factory" );
}
this.sessionFactoryOptions = sessionFactoryOptions;
this.sessionFactoryOptions = providedSessionFactoryOptions;
this.properties = createPropertiesFromMap(
metadata.getServiceRegistry().getService( ConfigurationService.class ).getSettings()
);
// TODO: these should be moved into SessionFactoryOptions
this.settings = new SettingsFactory().buildSettings(
properties,
metadata.getServiceRegistry()
);
this.settings = sessionFactoryOptions.getSettings();
this.serviceRegistry =
sessionFactoryOptions.getServiceRegistry()
@ -714,17 +736,16 @@ public final class SessionFactoryImpl
// TODO: get SQL functions from a new service
// this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() );
if ( observer != null ) {
this.observer.addObserver( observer );
if ( sessionFactoryOptions.getSessionFactoryObservers() != null ) {
for ( SessionFactoryObserver observer : sessionFactoryOptions.getSessionFactoryObservers() ) {
this.observer.addObserver( observer );
}
}
this.typeResolver = metadata.getTypeResolver().scope( this );
this.typeHelper = new TypeLocatorImpl( typeResolver );
this.filters = new HashMap<String, FilterDefinition>();
for ( FilterDefinition filterDefinition : metadata.getFilterDefinitions() ) {
filters.put( filterDefinition.getFilterName(), filterDefinition );
}
this.filters = Collections.unmodifiableMap( metadata.getFilterDefinitions() );
if ( debugEnabled ) {
LOG.debugf( "Session factory constructed with filter configurations : %s", filters );
@ -772,14 +793,21 @@ public final class SessionFactoryImpl
// Prepare persisters and link them up with their cache
// region/access-strategy
final MetamodelBuilder jpaMetamodelBuilder = new MetamodelBuilder(
this,
JpaMetaModelPopulationSetting.parse(
properties.getProperty( AvailableSettings.JPA_METAMODEL_POPULATION )
)
);
StringBuilder stringBuilder = new StringBuilder();
if ( settings.getCacheRegionPrefix() != null) {
stringBuilder
.append( settings.getCacheRegionPrefix() )
.append( '.' );
}
RegionFactory regionFactory = cacheAccess.getRegionFactory();
final String cacheRegionPrefix = stringBuilder.toString();
entityPersisters = new HashMap<String,EntityPersister>();
Map<String, RegionAccessStrategy> entityAccessStrategies = new HashMap<String, RegionAccessStrategy>();
Map<String,ClassMetadata> classMeta = new HashMap<String,ClassMetadata>();
@ -791,16 +819,18 @@ public final class SessionFactoryImpl
EntityRegionAccessStrategy accessStrategy = null;
if ( settings.isSecondLevelCacheEnabled() &&
rootEntityBinding.getHierarchyDetails().getCaching() != null &&
model.getHierarchyDetails().getCaching() != null &&
model.getHierarchyDetails().getCaching().getAccessType() != null ) {
model.getHierarchyDetails().getCaching() != null ) {
final String cacheRegionName = cacheRegionPrefix + rootEntityBinding.getHierarchyDetails().getCaching().getRegion();
accessStrategy = EntityRegionAccessStrategy.class.cast( entityAccessStrategies.get( cacheRegionName ) );
if ( accessStrategy == null ) {
final AccessType accessType = model.getHierarchyDetails().getCaching().getAccessType();
AccessType accessType = model.getHierarchyDetails().getCaching().getAccessType();
if ( accessType == null ) {
accessType = regionFactory.getDefaultAccessType();
}
if ( traceEnabled ) {
LOG.tracev( "Building cache for entity data [{0}]", model.getEntity().getName() );
}
EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion(
EntityRegion entityRegion = regionFactory.buildEntityRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
accessStrategy = entityRegion.buildAccessStrategy( accessType );
@ -808,11 +838,47 @@ public final class SessionFactoryImpl
cacheAccess.addCacheRegion( cacheRegionName, entityRegion );
}
}
NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null;
if ( settings.isSecondLevelCacheEnabled() &&
rootEntityBinding.getHierarchyDetails().getNaturalIdCaching() != null &&
model.getHierarchyDetails().getNaturalIdCaching() != null ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + rootEntityBinding.getHierarchyDetails()
.getNaturalIdCaching()
.getRegion();
naturalIdAccessStrategy = (NaturalIdRegionAccessStrategy) entityAccessStrategies.get(
naturalIdCacheRegionName
);
if ( naturalIdAccessStrategy == null ) {
final CacheDataDescriptionImpl naturaIdCacheDataDescription = CacheDataDescriptionImpl.decode( model );
NaturalIdRegion naturalIdRegion = null;
try {
naturalIdRegion = regionFactory.buildNaturalIdRegion(
naturalIdCacheRegionName,
properties,
naturaIdCacheDataDescription
);
}
catch ( UnsupportedOperationException e ) {
LOG.warnf(
"Shared cache region factory [%s] does not support natural id caching; " +
"shared NaturalId caching will be disabled for not be enabled for %s",
regionFactory.getClass().getName(),
model.getEntity().getName()
);
}
if ( naturalIdRegion != null ) {
naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() );
entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy );
cacheAccess.addCacheRegion( naturalIdCacheRegionName, naturalIdRegion );
}
}
}
EntityPersister cp = serviceRegistry.getService( PersisterFactory.class ).createEntityPersister(
model, accessStrategy, this, metadata
model, accessStrategy, naturalIdAccessStrategy, this, metadata
);
entityPersisters.put( model.getEntity().getName(), cp );
classMeta.put( model.getEntity().getName(), cp.getClassMetadata() );
jpaMetamodelBuilder.add( model );
}
this.classMetadata = Collections.unmodifiableMap(classMeta);
@ -828,19 +894,32 @@ public final class SessionFactoryImpl
"AbstractPluralAttributeBinding has a Singular attribute defined: " + model.getAttribute().getName()
);
}
final String cacheRegionName = cacheRegionPrefix + model.getCaching().getRegion();
final AccessType accessType = model.getCaching().getAccessType();
CollectionRegionAccessStrategy accessStrategy = null;
if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
if ( traceEnabled ) {
LOG.tracev( "Building cache for collection data [{0}]", model.getAttribute().getRole() );
if ( settings.isSecondLevelCacheEnabled() &&
model.getCaching() != null ) {
final String cacheRegionName = cacheRegionPrefix + model.getCaching().getRegion();
AccessType accessType = model.getCaching().getAccessType();
if( accessType == null ){
accessType = regionFactory.getDefaultAccessType();
}
CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion(
if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
if ( traceEnabled ) {
LOG.tracev( "Building cache for collection data [{0}]", model.getAttribute().getRole() );
}
CollectionRegion collectionRegion = regionFactory.buildCollectionRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );
}
CollectionRegion collectionRegion = regionFactory.buildCollectionRegion(
cacheRegionName, properties, CacheDataDescriptionImpl.decode( model )
);
accessStrategy = collectionRegion.buildAccessStrategy( accessType );
entityAccessStrategies.put( cacheRegionName, accessStrategy );
cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );
cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );
}
CollectionPersister persister = serviceRegistry
.getService( PersisterFactory.class )
@ -879,26 +958,32 @@ public final class SessionFactoryImpl
namedQueryRepository = new NamedQueryRepository(
metadata.getNamedQueryDefinitions(),
metadata.getNamedNativeQueryDefinitions(),
metadata.getResultSetMappingDefinitions(),
metadata.getResultSetMappingDefinitions().values(),
new HashMap<String, ProcedureCallMemento>( )
);
imports = new HashMap<String,String>();
for ( Map.Entry<String,String> importEntry : metadata.getImports() ) {
for ( Map.Entry<String,String> importEntry : metadata.getImports().entrySet() ) {
imports.put( importEntry.getKey(), importEntry.getValue() );
}
// after *all* persisters and named queries are registered
Iterator iter = entityPersisters.values().iterator();
while ( iter.hasNext() ) {
final EntityPersister persister = ( ( EntityPersister ) iter.next() );
for ( EntityPersister persister : entityPersisters.values() ) {
persister.generateEntityDefinition();
}
for ( EntityPersister persister : entityPersisters.values() ) {
persister.postInstantiate();
registerEntityNameResolvers( persister );
}
iter = collectionPersisters.values().iterator();
while ( iter.hasNext() ) {
final CollectionPersister persister = ( ( CollectionPersister ) iter.next() );
if ( sessionFactoryOptions.getEntityNameResolvers() != null ) {
for ( EntityNameResolver resolver : sessionFactoryOptions.getEntityNameResolvers() ) {
registerEntityNameResolver( resolver );
}
}
for ( CollectionPersister persister : collectionPersisters.values() ) {
persister.postInstantiate();
}
@ -923,12 +1008,29 @@ public final class SessionFactoryImpl
LOG.debug("Instantiated session factory");
}
// TODO: FIX this
//settings.getMultiTableBulkIdStrategy().prepare(
// jdbcServices,
// buildLocalConnectionAccess(),
// mapp,
// metadata,
// properties
//);
if ( settings.isAutoCreateSchema() ) {
new SchemaExport( metadata )
.setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) )
.create( false, true );
}
// TODO: implement these for new metamodel
//if ( settings.isAutoUpdateSchema() ) {
// new SchemaUpdate( metadata ).execute( false, true );
//}
//if ( settings.isAutoValidateSchema() ) {
// new SchemaValidator( metadata ).validate();
//}
if ( settings.isAutoDropSchema() ) {
schemaExport = new SchemaExport( metadata )
.setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) );
@ -953,9 +1055,9 @@ public final class SessionFactoryImpl
// this needs to happen after persisters are all ready to go...
this.fetchProfiles = new HashMap<String,FetchProfile>();
for ( org.hibernate.metamodel.binding.FetchProfile mappingProfile : metadata.getFetchProfiles() ) {
for ( org.hibernate.metamodel.spi.binding.FetchProfile mappingProfile : metadata.getFetchProfiles() ) {
final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() );
for ( org.hibernate.metamodel.binding.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) {
for ( org.hibernate.metamodel.spi.binding.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) {
// resolve the persister owning the fetch
final String entityName = getImportedClassName( mappingFetch.getEntity() );
final EntityPersister owner = entityName == null ? null : entityPersisters.get( entityName );
@ -982,10 +1084,10 @@ public final class SessionFactoryImpl
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
}
this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy();
this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( null );
this.transactionEnvironment = new TransactionEnvironmentImpl( this );
this.observer.sessionFactoryCreated( this );
this.jpaMetamodel = jpaMetamodelBuilder.buildMetamodel();
}
@SuppressWarnings( {"unchecked"} )
@ -1708,12 +1810,12 @@ public final class SessionFactoryImpl
@Override
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy() {
return customEntityDirtinessStrategy;
return sessionFactoryOptions.getCustomEntityDirtinessStrategy();
}
@Override
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() {
return currentTenantIdentifierResolver;
return sessionFactoryOptions.getCurrentTenantIdentifierResolver();
}

View File

@ -24,10 +24,22 @@
*/
package org.hibernate.internal.util;
import java.beans.Introspector;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.classmate.MemberResolver;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.ResolvedTypeWithMembers;
import com.fasterxml.classmate.TypeResolver;
import com.fasterxml.classmate.members.ResolvedField;
import com.fasterxml.classmate.members.ResolvedMethod;
import com.fasterxml.classmate.types.ResolvedArrayType;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
@ -60,6 +72,9 @@ public final class ReflectHelper {
private static final Method OBJECT_EQUALS;
private static final Method OBJECT_HASHCODE;
private static final TypeResolver TYPE_RESOLVER = new TypeResolver();
private static final MemberResolver MEMBER_RESOLVER = new MemberResolver( TYPE_RESOLVER );
static {
Method eq;
Method hash;
@ -378,4 +393,92 @@ public final class ReflectHelper {
}
}
/**
* Process bean properties getter by applying the JavaBean naming conventions.
*
* @param member the member for which to get the property name.
*
* @return The bean method name with the "is" or "get" prefix stripped off, {@code null}
* the method name id not according to the JavaBeans standard.
*/
public static String getPropertyName(Member member) {
String name = null;
if ( member instanceof Field ) {
name = member.getName();
}
if ( member instanceof Method ) {
String methodName = member.getName();
if ( methodName.startsWith( "is" ) ) {
name = Introspector.decapitalize( methodName.substring( 2 ) );
}
else if ( methodName.startsWith( "has" ) ) {
name = Introspector.decapitalize( methodName.substring( 3 ) );
}
else if ( methodName.startsWith( "get" ) ) {
name = Introspector.decapitalize( methodName.substring( 3 ) );
}
}
return name;
}
public static boolean isProperty(Member m) {
if ( m instanceof Method ) {
Method method = (Method) m;
return !method.isSynthetic()
&& !method.isBridge()
&& !Modifier.isStatic( method.getModifiers() )
&& method.getParameterTypes().length == 0
&& ( method.getName().startsWith( "get" ) || method.getName().startsWith( "is" ) );
}
else {
return !Modifier.isTransient( m.getModifiers() ) && !m.isSynthetic();
}
}
/**
* Returns a Set of field types in the given class. However, for Collection
* and Map fields, the value and key types are returned instead of the
* Iterable class itself.
*
* @param clazz
* @return Set<Class<?>>
*/
// TODO: This should be moved out of ReflectHelper. Partial duplication with
// AnnotationBindingContextImpl#resolveMemberTypes
public static Set<Class<?>> getMemberTypes( Class<?> clazz ) {
Set<Class<?>> fieldTypes = new HashSet<Class<?>>();
ResolvedType resolvedType = TYPE_RESOLVER.resolve( clazz );
ResolvedTypeWithMembers resolvedTypes = MEMBER_RESOLVER.resolve( resolvedType, null, null );
ResolvedField[] resolvedFields = resolvedTypes.getMemberFields();
for ( ResolvedField resolvedField : resolvedFields ) {
resolveAllTypes( resolvedField.getType(), fieldTypes );
}
// TODO: This should really just be checking getters, but for now do everything.
ResolvedMethod[] resolvedMethods = resolvedTypes.getMemberMethods();
for ( ResolvedMethod resolvedMethod : resolvedMethods ) {
if ( resolvedMethod.getReturnType() != null ) {
resolveAllTypes( resolvedMethod.getReturnType(), fieldTypes );
}
}
return fieldTypes;
}
private static void resolveAllTypes(ResolvedType fieldType, Set<Class<?>> fieldTypes) {
if ( fieldType instanceof ResolvedArrayType ) {
ResolvedArrayType arrayType = (ResolvedArrayType) fieldType;
resolveAllTypes( arrayType.getArrayElementType(), fieldTypes );
} else {
fieldTypes.add( fieldType.getErasedType() );
}
for ( ResolvedType typeParameter : fieldType.getTypeBindings().getTypeParameters() ) {
resolveAllTypes( typeParameter, fieldTypes );
}
}
}

View File

@ -39,6 +39,7 @@ public final class StringHelper {
private static final int ALIAS_TRUNCATE_LENGTH = 10;
public static final String WHITESPACE = " \n\r\f\t";
public static final String [] EMPTY_STRINGS = new String[0];
private StringHelper() { /* static methods only - hide constructor */
}
@ -454,6 +455,10 @@ public final class StringHelper {
return string == null || string.length() == 0;
}
public static boolean isEmptyOrWhiteSpace(String string){
return isEmpty( string ) || isEmpty( string.trim() );
}
public static String qualify(String prefix, String name) {
if ( name == null || prefix == null ) {
throw new NullPointerException( "prefix or name were null attempting to build qualified name" );

View File

@ -339,6 +339,17 @@ public final class ArrayHelper {
return PRIME_NUMER * seed + i;
}
/**
* Returns {@code true} if the specified array is {@code null} or empty.
*
* @param array the array to check.
* @return {@code true} if the specified array is {@code null} or empty.
*/
public static boolean isEmpty(final Object[] array) {
return array == null || array.length == 0;
}
/**
* Compare 2 arrays only at the first level
*/

View File

@ -156,7 +156,11 @@ public final class CollectionHelper {
return collection == null || collection.isEmpty();
}
public static boolean isEmpty(Map map) {
public static boolean isEmpty(Iterable iterable){
return iterable == null || !iterable.iterator().hasNext();
}
public static boolean isEmpty(Map map) {
return map == null || map.isEmpty();
}
@ -172,6 +176,23 @@ public final class CollectionHelper {
return objects == null || objects.length==0;
}
public static boolean isCollectionOrArray(Class clazz) {
if ( clazz == null ) {
return false;
}
if ( Collection.class.isAssignableFrom( clazz ) ) {
return true;
}
if ( Map.class.isAssignableFrom( clazz ) ) {
return true;
}
// TODO: why is the next block commented out???
// if ( clazz.isArray() ) {
// return true;
// }
return false;
}
public static <X,Y> Map<X, Y> makeCopy(Map<X, Y> map) {
final Map<X,Y> copy = mapOfSize( map.size() + 1 );
copy.putAll( map );

View File

@ -224,7 +224,8 @@ public class MappingReader {
public static enum SupportedOrmXsdVersion {
ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ),
ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd" ),
ORM_2_1( "org/hibernate/jpa/orm_2_1.xsd" );
ORM_2_1( "org/hibernate/jpa/orm_2_1.xsd" ),
HBM_4_0( "org/hibernate/hibernate-mapping-4.0.xsd");
private final String schemaResourceName;
@ -242,6 +243,9 @@ public class MappingReader {
else if ( "2.1".equals( name ) ) {
return ORM_2_1;
}
else if ( "4.0".equals( name ) ) {
return HBM_4_0;
}
throw new UnsupportedOrmXsdVersionException( name, origin );
}
@ -264,7 +268,7 @@ public class MappingReader {
}
}
private static URL resolveLocalSchemaUrl(String schemaName) {
public static URL resolveLocalSchemaUrl(String schemaName) {
URL url = MappingReader.class.getClassLoader().getResource( schemaName );
if ( url == null ) {
throw new XmlInfrastructureException( "Unable to locate schema [" + schemaName + "] via classpath" );
@ -272,7 +276,11 @@ public class MappingReader {
return url;
}
private static Schema resolveLocalSchema(URL schemaUrl) {
public static Schema resolveLocalSchema(String schemaName){
return resolveLocalSchema( resolveLocalSchemaUrl( schemaName ) );
}
public static Schema resolveLocalSchema(URL schemaUrl) {
try {
InputStream schemaStream = schemaUrl.openStream();
@ -326,7 +334,7 @@ public class MappingReader {
if ( errorHandler.hasErrors() ) {
throw errorHandler.getErrors().get( 0 );
}
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
return new XmlDocumentImpl( document, origin );
}
catch ( Exception e ) {
if ( LOG.isDebugEnabled() ) {
@ -344,7 +352,7 @@ public class MappingReader {
errorHandler.logErrors();
throw errorHandler.getErrors().get( 0 );
}
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
return new XmlDocumentImpl( document, origin );
}
catch ( Exception e2 ) {
if ( LOG.isDebugEnabled() ) {
@ -361,7 +369,7 @@ public class MappingReader {
errorHandler.logErrors();
throw errorHandler.getErrors().get( 0 );
}
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
return new XmlDocumentImpl( document, origin );
}
catch ( Exception e3 ) {
if ( LOG.isDebugEnabled() ) {
@ -382,13 +390,13 @@ public class MappingReader {
if ( "orm_2_1.xsd".equals( xsd ) ) {
saxReader.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://xmlns.jcp.org/xml/ns/persistence/orm " + xsd
LocalXmlResourceResolver.SECOND_JPA_ORM_NS + " " + xsd
);
}
else {
saxReader.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://java.sun.com/xml/ns/persistence/orm " + xsd
LocalXmlResourceResolver.INITIAL_JPA_ORM_NS + " " + xsd
);
}
}

View File

@ -0,0 +1,190 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jaxb.internal;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.validation.Schema;
import org.jboss.logging.Logger;
import org.hibernate.internal.util.xml.BufferedXMLEventReader;
import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
import org.hibernate.jaxb.spi.JaxbRoot;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.service.ServiceRegistry;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
abstract class AbstractJaxbProcessor {
protected static final Logger log = Logger.getLogger( AbstractJaxbProcessor.class );
// public static final String VALIDATE_XML_SETTING = "hibernate.xml.validate";
protected final ServiceRegistry serviceRegistry;
protected final boolean validateXml;
public AbstractJaxbProcessor(ServiceRegistry serviceRegistry) {
this( serviceRegistry, true );
// this(
// serviceRegistry,
// serviceRegistry.getService( ConfigurationService.class ).getSetting(
// VALIDATE_XML_SETTING,
// StandardConverters.BOOLEAN,
// true
// )
// );
}
public AbstractJaxbProcessor(ServiceRegistry serviceRegistry, boolean validateXml) {
this.serviceRegistry = serviceRegistry;
this.validateXml = validateXml;
}
public JaxbRoot unmarshal(InputStream stream, Origin origin) {
try {
BufferedXMLEventReader staxReader = new BufferedXMLEventReader(staxFactory().createXMLEventReader( stream ), 100);
try {
return unmarshal( staxReader, origin );
}
finally {
try {
staxReader.close();
}
catch ( Exception ignore ) {
}
}
}
catch ( XMLStreamException e ) {
throw new MappingException( "Unable to create stax reader", e, origin );
}
}
private XMLInputFactory staxFactory;
private XMLInputFactory staxFactory() {
if ( staxFactory == null ) {
staxFactory = buildStaxFactory();
}
return staxFactory;
}
@SuppressWarnings( { "UnnecessaryLocalVariable" })
private XMLInputFactory buildStaxFactory() {
XMLInputFactory staxFactory = XMLInputFactory.newInstance();
staxFactory.setXMLResolver( LocalXmlResourceResolver.INSTANCE );
return staxFactory;
}
@SuppressWarnings( { "unchecked" })
private JaxbRoot unmarshal(XMLEventReader staxEventReader, final Origin origin) {
XMLEvent event;
try {
event = staxEventReader.peek();
while ( event != null && !event.isStartElement() ) {
staxEventReader.nextEvent();
event = staxEventReader.peek();
}
}
catch ( Exception e ) {
throw new MappingException( "Error accessing stax stream", e, origin );
}
if ( event == null ) {
throw new MappingException( "Could not locate root element", origin );
}
final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler();
try {
Schema schema = getSchema(event, origin);
staxEventReader = wrapReader( staxEventReader, event );
JAXBContext jaxbContext =getJaxbContext(event);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema( schema );
unmarshaller.setEventHandler( handler );
final Object target = unmarshaller.unmarshal( staxEventReader );
return new JaxbRoot( target, origin );
}
catch ( JAXBException e ) {
StringBuilder builder = new StringBuilder();
builder.append( "Unable to perform unmarshalling at line number " );
builder.append( handler.getLineNumber() );
builder.append( " and column " );
builder.append( handler.getColumnNumber() );
builder.append( ". Message: " );
builder.append( handler.getMessage() );
throw new MappingException( builder.toString(), e, origin );
}
}
protected abstract JAXBContext getJaxbContext(XMLEvent event) throws JAXBException;
protected abstract Schema getSchema(XMLEvent event, Origin origin) throws JAXBException;
protected XMLEventReader wrapReader(XMLEventReader xmlEventReader, XMLEvent event){
return xmlEventReader;
}
protected static boolean isNamespaced(StartElement startElement) {
return ! "".equals( startElement.getName().getNamespaceURI() );
}
static class ContextProvidingValidationEventHandler implements ValidationEventHandler {
private int lineNumber;
private int columnNumber;
private String message;
@Override
public boolean handleEvent(ValidationEvent validationEvent) {
ValidationEventLocator locator = validationEvent.getLocator();
lineNumber = locator.getLineNumber();
columnNumber = locator.getColumnNumber();
message = validationEvent.getMessage();
return false;
}
public int getLineNumber() {
return lineNumber;
}
public int getColumnNumber() {
return columnNumber;
}
public String getMessage() {
return message;
}
}
}

View File

@ -0,0 +1,85 @@
/*
* 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.jaxb.internal;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.XMLEvent;
import javax.xml.validation.Schema;
import org.jboss.logging.Logger;
import org.hibernate.internal.util.xml.MappingReader;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.jaxb.spi.cfg.JaxbHibernateConfiguration;
import org.hibernate.service.ServiceRegistry;
/**
* @author Steve Ebersole
*/
public class JaxbConfigurationProcessor extends AbstractJaxbProcessor {
private static final Logger log = Logger.getLogger( JaxbConfigurationProcessor.class );
public static final String HIBERNATE_CONFIGURATION_URI = "http://www.hibernate.org/xsd/hibernate-configuration";
public JaxbConfigurationProcessor(ServiceRegistry serviceRegistry) {
this( serviceRegistry, true );
}
public JaxbConfigurationProcessor(ServiceRegistry serviceRegistry, boolean validateXml) {
super(serviceRegistry, validateXml);
}
@Override
protected XMLEventReader wrapReader(XMLEventReader xmlEventReader, XMLEvent event) {
if ( !isNamespaced( event.asStartElement() ) ) {
// if the elements are not namespaced, wrap the reader in a reader which will namespace them as pulled.
log.debug( "cfg.xml document did not define namespaces; wrapping in custom event reader to introduce namespace information" );
return new NamespaceAddingEventReader( xmlEventReader, HIBERNATE_CONFIGURATION_URI );
}
return super.wrapReader( xmlEventReader, event );
}
@Override
protected JAXBContext getJaxbContext(XMLEvent event) throws JAXBException{
return JAXBContext.newInstance( JaxbHibernateConfiguration.class );
}
@Override
protected Schema getSchema(XMLEvent event, Origin origin) throws JAXBException {
if ( schema == null ) {
schema = MappingReader.resolveLocalSchema( "org/hibernate/hibernate-configuration-4.0.xsd" );
}
return schema;
}
private Schema schema;
}

View File

@ -0,0 +1,184 @@
/*
* 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.jaxb.internal;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import org.jboss.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
import org.hibernate.internal.util.xml.MappingReader;
import org.hibernate.internal.util.xml.OriginImpl;
import org.hibernate.jaxb.spi.JaxbRoot;
import org.hibernate.jaxb.spi.Origin;
import org.hibernate.jaxb.spi.hbm.JaxbHibernateMapping;
import org.hibernate.jaxb.spi.orm.JaxbEntityMappings;
import org.hibernate.metamodel.spi.source.MappingException;
import org.hibernate.service.ServiceRegistry;
/**
* Loads {@code hbm.xml} and {@code orm.xml} files and processes them using StAX and JAXB.
*
* @author Steve Ebersole
* @author Hardy Ferentschik
*/
public class JaxbMappingProcessor extends AbstractJaxbProcessor{
private static final Logger log = Logger.getLogger( JaxbMappingProcessor.class );
public static final String HIBERNATE_MAPPING_URI = "http://www.hibernate.org/xsd/hibernate-mapping";
public JaxbMappingProcessor(ServiceRegistry serviceRegistry) {
this( serviceRegistry, true );
}
public JaxbMappingProcessor(ServiceRegistry serviceRegistry, boolean validateXml) {
super(serviceRegistry, validateXml);
}
@Override
protected JAXBContext getJaxbContext(XMLEvent event) throws JAXBException {
final String elementName = event.asStartElement().getName().getLocalPart();
final Class jaxbTarget;
if ( "entity-mappings".equals( elementName ) ) {
jaxbTarget = JaxbEntityMappings.class;
}
else {
jaxbTarget = JaxbHibernateMapping.class;
}
return JAXBContext.newInstance( jaxbTarget );
}
@Override
protected Schema getSchema(XMLEvent event, Origin origin) throws JAXBException {
final String elementName = event.asStartElement().getName().getLocalPart();
final Schema validationSchema;
if ( "entity-mappings".equals( elementName ) ) {
final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
final String explicitVersion = attribute == null ? null : attribute.getValue();
validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion, origin ) : null;
}
else {
validationSchema = validateXml ? MappingReader.SupportedOrmXsdVersion.HBM_4_0.getSchema() : null;
}
return validationSchema;
}
@Override
protected XMLEventReader wrapReader(XMLEventReader staxEventReader, XMLEvent event) {
final String elementName = event.asStartElement().getName().getLocalPart();
if ( "entity-mappings".equals( elementName ) ) {
final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
final String explicitVersion = attribute == null ? null : attribute.getValue();
if ( !"2.1".equals( explicitVersion ) ) {
return new LegacyJPAEventReader(
staxEventReader,
LocalXmlResourceResolver.SECOND_JPA_ORM_NS
);
}
}
else {
if ( !isNamespaced( event.asStartElement() ) ) {
// if the elements are not namespaced, wrap the reader in a reader which will namespace them as pulled.
log.debug( "HBM mapping document did not define namespaces; wrapping in custom event reader to introduce namespace information" );
return new NamespaceAddingEventReader( staxEventReader, HIBERNATE_MAPPING_URI );
}
}
return super.wrapReader( staxEventReader, event );
}
private static final QName ORM_VERSION_ATTRIBUTE_QNAME = new QName( "version" );
@SuppressWarnings( { "unchecked" })
public JaxbRoot unmarshal(Document document, Origin origin) {
Element rootElement = document.getDocumentElement();
if ( rootElement == null ) {
throw new MappingException( "No root element found", origin );
}
final Schema validationSchema;
final Class jaxbTarget;
if ( "entity-mappings".equals( rootElement.getNodeName() ) ) {
final String explicitVersion = rootElement.getAttribute( "version" );
validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion, origin ) : null;
jaxbTarget = JaxbEntityMappings.class;
}
else {
validationSchema = validateXml ? MappingReader.SupportedOrmXsdVersion.HBM_4_0.getSchema() : null;
jaxbTarget = JaxbHibernateMapping.class;
}
final Object target;
try {
JAXBContext jaxbContext = JAXBContext.newInstance( jaxbTarget );
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema( validationSchema );
target = unmarshaller.unmarshal( new DOMSource( document ) );
}
catch ( JAXBException e ) {
throw new MappingException( "Unable to perform unmarshalling", e, origin );
}
return new JaxbRoot( target, origin );
}
private Schema resolveSupportedOrmXsd(String explicitVersion, Origin origin) {
if ( StringHelper.isEmpty( explicitVersion ) ) {
return MappingReader.SupportedOrmXsdVersion.ORM_2_1.getSchema();
}
// Here we always use JPA 2.1 schema to do the validation, since the {@link LegacyJPAEventReader} already
// transforms the legacy orm.xml to JPA 2.1 namespace and version.
//
// This may cause some problems, like a jpa 1.0 orm.xml having some element which is only available in the later
// version. It is "invalid" but due to the fact we're using the latest schema to do the validation, then
// it is "valid". Don't know if this will cause any problems, but let's do it for now.
//
// However, still check for the validity of the version by calling #parse. If someone explicitly uses a value
// that doesn't exist, we still need to throw the exception.
@SuppressWarnings("unused")
MappingReader.SupportedOrmXsdVersion version =
MappingReader.SupportedOrmXsdVersion.parse(
explicitVersion,
new OriginImpl( origin.getType().name(), origin.getName() )
);
// return version.getSchema();
return MappingReader.SupportedOrmXsdVersion.ORM_2_1.getSchema();
}
}

View File

@ -0,0 +1,140 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, 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.jaxb.internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
/**
*
* We're lying to the xml validator here :D
* <p/>
*
* Since JPA 2.1 changed its orm.xml namespace, so to support all versions
* <ul>
* <li>1.0</li>
* <li>2.0</li>
* <li>2.1</li>
* </ul>
*
* the validator must recognize all of these two namespaces.
*
* but it is very hard to do that, so we're making an assumption (because I really don't konw if this is true or not)
* here that JPA 2.1 is backward compatible w/ the old releases.
*
* So, there it comes, we just simply remove all legacy namespaces if it is an orm.xml and add the expected namespace
* , here is it JPA 2.1, to every elements in the xml.
*
* Finally, for the xml validator, it always see the JPA 2.1 namespace only, and it would be happy to do the validation.
*
* <p/>
* {@see HHH-8108} for more discussion.
*
* @author Strong Liu <stliu@hibernate.org>
*/
public class LegacyJPAEventReader extends EventReaderDelegate {
private final XMLEventFactory xmlEventFactory;
private final String namespaceUri;
public LegacyJPAEventReader(XMLEventReader reader, String namespaceUri) {
this( reader, XMLEventFactory.newInstance(), namespaceUri );
}
public LegacyJPAEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory, String namespaceUri) {
super( reader );
this.xmlEventFactory = xmlEventFactory;
this.namespaceUri = namespaceUri;
}
private StartElement withNamespace(StartElement startElement) {
Iterator<?> attributes;
Iterator<?> namespacesItr;
if ( "entity-mappings".equals( startElement.getName().getLocalPart() ) ) {
List<Attribute> st = new ArrayList<Attribute>();
Iterator itr = startElement.getAttributes();
while ( itr.hasNext() ) {
Attribute obj = (Attribute) itr.next();
if ( "version".equals( obj.getName().getLocalPart() ) ) {
if ( "".equals( obj.getName().getPrefix() ) ) {
st.add( xmlEventFactory.createAttribute( obj.getName(), "2.1" ) );
}
}
else {
st.add( obj );
}
}
attributes = st.iterator();
// otherwise, wrap the start element event to provide a default namespace mapping
final List<Namespace> namespaces = new ArrayList<Namespace>();
namespaces.add( xmlEventFactory.createNamespace( "", namespaceUri ) );
Iterator<?> originalNamespaces = startElement.getNamespaces();
while ( originalNamespaces.hasNext() ) {
Namespace ns = (Namespace) originalNamespaces.next();
if ( !LocalXmlResourceResolver.INITIAL_JPA_ORM_NS.equals( ns.getNamespaceURI() ) ) {
namespaces.add( ns );
}
}
namespacesItr = namespaces.iterator();
} else {
attributes = startElement.getAttributes();
namespacesItr = startElement.getNamespaces();
}
return xmlEventFactory.createStartElement(
new QName( namespaceUri, startElement.getName().getLocalPart() ),
attributes,
namespacesItr
);
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
return wrap( super.nextEvent() );
}
private XMLEvent wrap(XMLEvent event) {
if ( event!=null && event.isStartElement() ) {
return withNamespace( event.asStartElement() );
}
return event;
}
@Override
public XMLEvent peek() throws XMLStreamException {
return wrap( super.peek() );
}
}

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, 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.jaxb.internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
import org.hibernate.internal.util.xml.LocalXmlResourceResolver;
/**
* Used to wrap a StAX {@link XMLEventReader} in order to introduce namespaces into the underlying document. This
* is intended for temporary migration feature to allow legacy HBM mapping documents (DTD-based) to continue to
* parse correctly. This feature will go away eventually.
*
* @author Steve Ebersole
*/
public class NamespaceAddingEventReader extends EventReaderDelegate {
private final XMLEventFactory xmlEventFactory;
private final String namespaceUri;
public NamespaceAddingEventReader(XMLEventReader reader, String namespaceUri) {
this( reader, XMLEventFactory.newInstance(), namespaceUri );
}
public NamespaceAddingEventReader(XMLEventReader reader, XMLEventFactory xmlEventFactory, String namespaceUri) {
super( reader );
this.xmlEventFactory = xmlEventFactory;
this.namespaceUri = namespaceUri;
}
private StartElement withNamespace(StartElement startElement) {
// otherwise, wrap the start element event to provide a default namespace mapping
final List<Namespace> namespaces = new ArrayList<Namespace>();
namespaces.add( xmlEventFactory.createNamespace( "", namespaceUri ) );
Iterator<?> originalNamespaces = startElement.getNamespaces();
while ( originalNamespaces.hasNext() ) {
Namespace ns = (Namespace) originalNamespaces.next();
namespaces.add( ns );
}
return xmlEventFactory.createStartElement(
new QName( namespaceUri, startElement.getName().getLocalPart() ),
startElement.getAttributes(),
namespaces.iterator()
);
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
return wrap( super.nextEvent() );
}
private XMLEvent wrap(XMLEvent event) {
if ( event.isStartElement() ) {
return withNamespace( event.asStartElement() );
}
return event;
}
@Override
public XMLEvent peek() throws XMLStreamException {
return wrap( super.peek() );
}
}

View File

@ -0,0 +1,5 @@
package org.hibernate.jaxb;
/**
* Defines Hibernate's JAXB usage.
*/

View File

@ -21,7 +21,9 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.jaxb;
package org.hibernate.jaxb.spi;
import java.io.Serializable;
/**
* Holds information about a JAXB-unmarshalled XML document.
@ -29,7 +31,7 @@ package org.hibernate.internal.jaxb;
* @author Hardy Ferentschik
* @author Steve Ebersole
*/
public class JaxbRoot<T> {
public class JaxbRoot<T> implements Serializable {
private final T root;
private final Origin origin;

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.jaxb;
package org.hibernate.jaxb.spi;
import java.io.Serializable;
@ -57,4 +57,40 @@ public class Origin implements Serializable {
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( !( o instanceof Origin ) ) {
return false;
}
Origin origin = (Origin) o;
if ( name != null ? !name.equals( origin.name ) : origin.name != null ) {
return false;
}
if ( type != origin.type ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = type != null ? type.hashCode() : 0;
result = 31 * result + ( name != null ? name.hashCode() : 0 );
return result;
}
@Override
public String toString() {
return "Origin{" +
"name='" + name + '\'' +
", type=" + type +
'}';
}
}

View File

@ -22,7 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.jaxb;
package org.hibernate.jaxb.spi;
/**
* From what type of source did we obtain the data

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, 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.
@ -21,13 +21,13 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.jaxb.mapping.hbm;
package org.hibernate.jaxb.spi.hbm;
/**
* @author Steve Ebersole
*/
public interface CustomSqlElement {
public String getValue();
public boolean isCallable();
public JaxbCheckAttribute getCheck();
public interface ComponentSourceElement extends MetaAttributeContainer {
public String getAccess();
public String getClazz();
public String getName();
}

Some files were not shown because too many files have changed in this diff Show More