Skip to content

Commit

Permalink
HHH-18048 - Split notions of SessionFactory name and SessionFactory J…
Browse files Browse the repository at this point in the history
…NDI name
  • Loading branch information
sebersole committed May 2, 2024
1 parent c2f6abd commit 4035d96
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 50 deletions.
Expand Up @@ -137,6 +137,11 @@
* @author Steve Ebersole
*/
public interface SessionFactory extends EntityManagerFactory, Referenceable, Serializable, java.io.Closeable {
/**
* The JNDI name, used to bind the SessionFactory to JNDI
*/
String getJndiName();

/**
* Obtain a {@linkplain SessionBuilder session builder} for creating
* new {@link Session}s with certain customized options.
Expand Down
Expand Up @@ -82,7 +82,9 @@ public interface SessionFactoryBuilder {
*
* @return {@code this}, for method chaining
*
* @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_NAME
* @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_NAME_IS_JNDI
* @see org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_JNDI_NAME
*/
SessionFactoryBuilder applyNameAsJndiName(boolean isJndiName);

Expand Down
Expand Up @@ -23,19 +23,16 @@
* @author Gavin King
*/
class SessionFactoryObserverForRegistration implements SessionFactoryObserver {

private JndiService jndiService;
private boolean registeredInJndi;

@Override
public void sessionFactoryCreated(SessionFactory factory) {
final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) factory;
jndiService = sessionFactory.getServiceRegistry().getService( JndiService.class );
registeredInJndi = sessionFactory.getSessionFactoryOptions().isSessionFactoryNameAlsoJndiName();
SessionFactoryRegistry.INSTANCE.addSessionFactory(
sessionFactory.getUuid(),
sessionFactory.getName(),
registeredInJndi,
sessionFactory.getJndiName(),
sessionFactory,
jndiService
);
Expand All @@ -47,7 +44,7 @@ public void sessionFactoryClosed(SessionFactory factory) {
SessionFactoryRegistry.INSTANCE.removeSessionFactory(
sessionFactory.getUuid(),
sessionFactory.getName(),
registeredInJndi,
sessionFactory.getJndiName(),
jndiService
);
}
Expand Down
Expand Up @@ -170,7 +170,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
// SessionFactory behavior
private final boolean jpaBootstrap;
private String sessionFactoryName;
private boolean sessionFactoryNameAlsoJndiName;
private Boolean sessionFactoryNameAlsoJndiName;

// Session behavior
private boolean flushBeforeCompletionEnabled;
Expand Down Expand Up @@ -916,7 +916,7 @@ public String getSessionFactoryName() {
}

@Override
public boolean isSessionFactoryNameAlsoJndiName() {
public Boolean isSessionFactoryNameAlsoJndiName() {
return sessionFactoryNameAlsoJndiName;
}

Expand Down
Expand Up @@ -101,7 +101,7 @@ public String getSessionFactoryName() {
}

@Override
public boolean isSessionFactoryNameAlsoJndiName() {
public Boolean isSessionFactoryNameAlsoJndiName() {
return delegate.isSessionFactoryNameAlsoJndiName();
}

Expand Down
Expand Up @@ -85,10 +85,10 @@ default boolean isAllowRefreshDetachedEntity() {
}

/**
* The name to be used for the SessionFactory. This is used both in:<ul>
* <li>in-VM serialization</li>
* <li>JNDI binding, depending on {@link #isSessionFactoryNameAlsoJndiName}</li>
* </ul>
* The name to be used for the SessionFactory. This is used during in-VM serialization; see
* {@link org.hibernate.internal.SessionFactoryRegistry}.
* May also be used as a JNDI name depending on {@value org.hibernate.cfg.PersistenceSettings#SESSION_FACTORY_JNDI_NAME}
* and {@value org.hibernate.cfg.PersistenceSettings#SESSION_FACTORY_NAME_IS_JNDI}.
*
* @return The SessionFactory name
*/
Expand All @@ -100,7 +100,7 @@ default boolean isAllowRefreshDetachedEntity() {
*
* @return {@code true} if the SessionFactory name is also a JNDI name; {@code false} otherwise.
*/
boolean isSessionFactoryNameAlsoJndiName();
Boolean isSessionFactoryNameAlsoJndiName();

boolean isFlushBeforeCompletionEnabled();

Expand Down
Expand Up @@ -7,6 +7,7 @@
package org.hibernate.cfg;

import org.hibernate.Incubating;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;

import jakarta.persistence.spi.PersistenceUnitInfo;
Expand Down Expand Up @@ -61,16 +62,27 @@ public interface PersistenceSettings {
* Naming the SessionFactory allows for it to be properly serialized across JVMs as
* long as the same name is used on each JVM.
* <p>
* If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true}, this is also the
* name under which the SessionFactory is bound into JNDI on startup and from which
* it can be obtained from JNDI.
* If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true}, this name will
* also be used as {@link #SESSION_FACTORY_JNDI_NAME}.
*
* @see #SESSION_FACTORY_NAME_IS_JNDI
* @see #SESSION_FACTORY_JNDI_NAME
* @see org.hibernate.internal.SessionFactoryRegistry
* @see org.hibernate.boot.SessionFactoryBuilder#applyName(String)
*/
String SESSION_FACTORY_NAME = "hibernate.session_factory_name";

/**
* An optional name used to bind the SessionFactory into JNDI.
* <p>
* If {@link #SESSION_FACTORY_NAME_IS_JNDI} is set to {@code true},
* {@link #SESSION_FACTORY_NAME} will be used as the JNDI name
*
* @see #SESSION_FACTORY_NAME_IS_JNDI
* @see org.hibernate.internal.SessionFactoryRegistry
* @see org.hibernate.boot.SessionFactoryBuilder#applyName(String)
*/
String SESSION_FACTORY_JNDI_NAME = "hibernate.session_factory_jndi_name";

/**
* Does the value defined by {@link #SESSION_FACTORY_NAME} represent a JNDI namespace
* into which the {@link org.hibernate.SessionFactory} should be bound and made accessible?
Expand All @@ -83,6 +95,10 @@ public interface PersistenceSettings {
*
* @see #SESSION_FACTORY_NAME
* @see org.hibernate.boot.SessionFactoryBuilder#applyNameAsJndiName(boolean)
*
* @settingDefault {@code true} if {@link SessionFactory#getName()} comes from
* {@value #SESSION_FACTORY_NAME}; {@code false} if there is no {@link SessionFactory#getName()}
* or if it comes from {@value #PERSISTENCE_UNIT_NAME}
*/
String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi";

Expand Down
Expand Up @@ -340,6 +340,11 @@ public String getName() {
return delegate.getName();
}

@Override
public String getJndiName() {
return delegate.getJndiName();
}

@Override
public TypeConfiguration getTypeConfiguration() {
return delegate.getTypeConfiguration();
Expand Down
Expand Up @@ -60,7 +60,6 @@
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.profile.FetchProfile;
Expand Down Expand Up @@ -143,6 +142,8 @@
import static org.hibernate.cfg.AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_VALIDATION_FACTORY;
import static org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY;
import static org.hibernate.cfg.PersistenceSettings.PERSISTENCE_UNIT_NAME;
import static org.hibernate.cfg.PersistenceSettings.SESSION_FACTORY_JNDI_NAME;
import static org.hibernate.engine.config.spi.StandardConverters.STRING;
import static org.hibernate.internal.FetchProfileHelper.getFetchProfiles;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
Expand Down Expand Up @@ -175,6 +176,7 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class );

private final String name;
private final String jndiName;
private final String uuid;

private transient volatile Status status = Status.OPEN;
Expand Down Expand Up @@ -237,6 +239,7 @@ public SessionFactoryImpl(
bootMetamodel.initSessionFactory( this );

name = getSessionFactoryName( options, serviceRegistry );
jndiName = determineJndiName( name, options, serviceRegistry );
uuid = options.getUuid();

jdbcServices = serviceRegistry.requireService( JdbcServices.class );
Expand Down Expand Up @@ -345,7 +348,7 @@ public SessionFactoryImpl(
LOG.debug( "Instantiated SessionFactory" );
}

private void deprecationCheck(Map<String, Object> settings) {
private static void deprecationCheck(Map<String, Object> settings) {
for ( String s:settings.keySet() ) {
switch (s) {
case "hibernate.hql.bulk_id_strategy.global_temporary.create_tables":
Expand Down Expand Up @@ -574,6 +577,23 @@ private static String getSessionFactoryName(SessionFactoryOptions options, Sessi
return null;
}

private String determineJndiName(
String name,
SessionFactoryOptions options,
SessionFactoryServiceRegistry serviceRegistry) {
final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class );
assert cfgService != null;
final String explicitJndiName = cfgService.getSetting( SESSION_FACTORY_JNDI_NAME, STRING );
if ( StringHelper.isNotEmpty( explicitJndiName ) ) {
return explicitJndiName;
}

final String puName = cfgService.getSetting( PERSISTENCE_UNIT_NAME, STRING );
// do not use name for JNDI if explicitly asked not to or if name comes from JPA persistence-unit name
final boolean nameIsNotJndiName = options.isSessionFactoryNameAlsoJndiName() == Boolean.FALSE || StringHelper.isNotEmpty( puName );
return !nameIsNotJndiName ? name : null;
}

private SessionBuilderImpl createDefaultSessionOpenOptionsIfPossible() {
final CurrentTenantIdentifierResolver<Object> currentTenantIdentifierResolver = getCurrentTenantIdentifierResolver();
if ( currentTenantIdentifierResolver == null ) {
Expand Down Expand Up @@ -724,6 +744,11 @@ public String getName() {
return name;
}

@Override
public String getJndiName() {
return jndiName;
}

@Override
public TypeConfiguration getTypeConfiguration() {
return runtimeMetamodels.getMappingMetamodel().getTypeConfiguration();
Expand Down Expand Up @@ -1765,7 +1790,7 @@ static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException
return (SessionFactoryImpl) locateSessionFactoryOnDeserialization( uuid, name );
}

private void maskOutSensitiveInformation(Map<String, Object> props) {
private static void maskOutSensitiveInformation(Map<String, Object> props) {
maskOutIfSet( props, AvailableSettings.JPA_JDBC_USER );
maskOutIfSet( props, AvailableSettings.JPA_JDBC_PASSWORD );
maskOutIfSet( props, AvailableSettings.JAKARTA_JDBC_USER );
Expand All @@ -1774,13 +1799,13 @@ private void maskOutSensitiveInformation(Map<String, Object> props) {
maskOutIfSet( props, AvailableSettings.PASS );
}

private void maskOutIfSet(Map<String, Object> props, String setting) {
private static void maskOutIfSet(Map<String, Object> props, String setting) {
if ( props.containsKey( setting ) ) {
props.put( setting, "****" );
}
}

private void logIfEmptyCompositesEnabled(Map<String, Object> props ) {
private static void logIfEmptyCompositesEnabled(Map<String, Object> props ) {
final boolean isEmptyCompositesEnabled = getBoolean( CREATE_EMPTY_COMPOSITES_ENABLED, props );
if ( isEmptyCompositesEnabled ) {
LOG.emptyCompositesEnabled();
Expand Down
Expand Up @@ -57,14 +57,14 @@ private SessionFactoryRegistry() {
*
* @param uuid The uuid under which to register the SessionFactory
* @param name The optional name under which to register the SessionFactory
* @param isNameAlsoJndiName Is name, if provided, also a JNDI name?
* @param jndiName An optional name to use for binding the SessionFactory into JNDI
* @param instance The SessionFactory instance
* @param jndiService The JNDI service, so we can register a listener if name is a JNDI name
*/
public void addSessionFactory(
String uuid,
String name,
boolean isNameAlsoJndiName,
String jndiName,
SessionFactoryImplementor instance,
JndiService jndiService) {
if ( uuid == null ) {
Expand All @@ -77,25 +77,28 @@ public void addSessionFactory(
nameUuidXref.put( name, uuid );
}

if ( name == null || !isNameAlsoJndiName ) {
if ( jndiName == null ) {
LOG.debug( "Not binding SessionFactory to JNDI, no JNDI name configured" );
return;
}

LOG.debugf( "Attempting to bind SessionFactory [%s] to JNDI", name );
bindToJndi( jndiName, instance, jndiService );
}

private void bindToJndi(String jndiName, SessionFactoryImplementor instance, JndiService jndiService) {
try {
jndiService.bind( name, instance );
LOG.factoryBoundToJndiName( name );
LOG.debugf( "Attempting to bind SessionFactory [%s] to JNDI", jndiName );
jndiService.bind( jndiName, instance );
LOG.factoryBoundToJndiName( jndiName );
try {
jndiService.addListener( name, listener );
jndiService.addListener( jndiName, listener );
}
catch (Exception e) {
LOG.couldNotBindJndiListener();
}
}
catch (JndiNameException e) {
LOG.invalidJndiName( name, e );
LOG.invalidJndiName( jndiName, e );
}
catch (JndiException e) {
LOG.unableToBindFactoryToJndi( e );
Expand All @@ -107,29 +110,29 @@ public void addSessionFactory(
*
* @param uuid The uuid
* @param name The optional name
* @param isNameAlsoJndiName Is name, if provided, also a JNDI name?
* @param jndiName An optional name to use for binding the SessionFactory nto JNDI
* @param jndiService The JNDI service
*/
public void removeSessionFactory(
String uuid,
String name,
boolean isNameAlsoJndiName,
String jndiName,
JndiService jndiService) {
if ( name != null ) {
nameUuidXref.remove( name );
}

if ( isNameAlsoJndiName ) {
try {
LOG.tracef( "Unbinding SessionFactory from JNDI : %s", name );
jndiService.unbind( name );
LOG.factoryUnboundFromJndiName( name );
}
catch (JndiNameException e) {
LOG.invalidJndiName( name, e );
}
catch (JndiException e) {
LOG.unableToUnbindFactoryFromJndi( e );
}
if ( jndiName != null ) {
try {
LOG.tracef( "Unbinding SessionFactory from JNDI : %s", jndiName );
jndiService.unbind( jndiName );
LOG.factoryUnboundFromJndiName( jndiName );
}
catch (JndiNameException e) {
LOG.invalidJndiName( jndiName, e );
}
catch (JndiException e) {
LOG.unableToUnbindFactoryFromJndi( e );
}
}

Expand Down

0 comments on commit 4035d96

Please sign in to comment.