= Custom SessionFactory and Session Implementations Guide
:toc:

The two main contracts of Hibernate, `org.hibernate.SessionFactory` and `org.hibernate.Session`, are both
defined as interfaces which allows for custom implementations to be provided.  There are two high-level ways
in which custom implementations can be provided to users.  The first is to develop a custom bootstrap API
specific to the custom implementation.  The second way is to integrate with the Hibernate bootstrap API.
This guide will cover the second approach.


== Implementor contracts

A Hibernate naming convention is that SPI contracts extending API contracts are named with Implementor appended
to the API contract name.  For `SessionFactory` and `Session` that is `SessionFactoryImplementor` and
`SessionImplementor` respectively.  These SPI contracts extra information and functionality needed by internal
components as well as other SPI components.  Therefore, custom `SessionFactory` and `Session` should additionally
implement `org.hibernate.engine.spi.SessionFactoryImplementor` and `org.hibernate.engine.spi.SessionImplementor`.
See all pertinent JavaDocs for discussions of implementation details.


== Integration hooks

`org.hibernate.boot.SessionFactoryBuilder` is part of the Hibernate native bootstrap API where we want to configure
the `SessionFactory` to be built.  Third parties can hook into this process by supplying a
`org.hibernate.boot.spi.SessionFactoryBuilderFactory` via the Java ServiceLoader mechanism (see JavaDocs for
`java.util.ServiceLoader` if you are unfamiliar with this service discovery mechanism).  As you might guess from their
names, a `SessionFactoryBuilderFactory` is responsible for creating `SessionFactoryBuilder` instances and a
`SessionFactoryBuilder` is in turn responsible for creating `SessionFactory` instances.

`org.hibernate.boot.spi.SessionFactoryOptions` are the options ultimately passed to the `SessionFactory` being
built.  They represent the choices applied by the user via the `SessionFactoryBuilder` contract.  Custom integrations
can leverage this and the `SessionFactoryBuilder` to also expose custom option setting.


[[example1]]
.Custom SessionFactoryBuilderFactory with additional option
====
[source, JAVA]
----
public class CustomSessionFactoryBuilderFactory
		implements SessionFactoryBuilderFactory {
	@Override
	public SessionFactoryBuilder getSessionFactoryBuilder(
			MetadataImplementor metadata,
			SessionFactoryBuilderImplementor defaultBuilder) {
		return new CustomSessionFactoryBuilder( metadata, defaultBuilder );
	}
}

public class CustomSessionFactoryBuilder
		extends AbstractDelegatingSessionFactoryBuilder {
	private final MetadataImplementor metadata;

    private final boolean customSetting;

	public DelegatingSessionFactoryBuilder(
			MetadataImplementor metadata,
			SessionFactoryBuilderImplementor delegate) {
		super( delegate );
		this.metadata = metadata;

		// initialize customSetting, maybe based on config settings...
		ConfigurationService cfgService = metadata.getMetadataBuildingOptions()
				.getServiceRegistry()
				.getService( ConfigurationService.class );
		this.customSetting = cfgService.getSetting(
				"com.acme.domain.custom_setting",
				StandardConverters.BOOLEAN,
				true
		);
	}

	@Override
	public DelegatingSessionFactoryBuilder unwrap() {
	    return (DelegatingSessionFactoryBuilder) this;
	}

    public CustomSessionFactoryBuilder applyCustomSetting(boolean enabled) {
     	this.customSetting = enabled;
    	return this;
    }

	@Override
	public SessionFactory build() {
	    CustomSessionFactoryOptions options = new CustomSessionFactoryOptions(
	    		getDelegate().buildSessionFactoryOptions(),
	    		customSetting
	    );
	    return new CustomSessionFactory( metadata, options );
	}
}

public class CustomSessionFactoryOptions
		extends AbstractDelegatingSessionFactoryOptions {
    private final boolean customSetting;

	public CustomSessionFactoryOptions(
			SessionFactoryOptions baseOptions,
			boolean customSetting) {
		super( baseOptions );
		this.customSetting = customSetting;
	}

	public boolean getCustomSetting() {
		return customSetting;
	}
}
----
====

Users can then build your custom `SessionFactory` still using the normal Hibernate bootstrap.  In fact,
accepting defaults for your custom settings/options, their code does not even change.  Of course they
can also apply selections to your custom settings/options as well:



[[example2]]
.Example usage
====
[source, JAVA]
----
Metadata metadata = ...;

// The SessionFactory returned here is concretely
// a CustomSessionFactory
SessionFactory sf = metadata.getSessionFactoryBuilder()
		.unwrap( CustomSessionFactoryBuilder.class )
		.applyCustomSetting( false )
		.buildSessionFactory();
----
====