HHH-11017 - Migrate Integration Guide to AsciiDoctor

This commit is contained in:
Vlad Mihalcea 2016-08-02 16:45:36 +03:00
parent 7c361fee3a
commit 7d14223531
20 changed files with 757 additions and 108 deletions

View File

@ -18,13 +18,11 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath "org.jboss.jdocbook:gradle-jdocbook:1.2.2"
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2' classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
} }
} }
apply plugin: "java" apply plugin: "java"
apply plugin: "jdocbook"
apply plugin: 'org.asciidoctor.convert' apply plugin: 'org.asciidoctor.convert'
apply plugin: 'hibernate-matrix-testing' apply plugin: 'hibernate-matrix-testing'
@ -52,10 +50,6 @@ dependencies {
// asciidoctor 'org.asciidoctor:asciidoctorj:1.5.2' // asciidoctor 'org.asciidoctor:asciidoctorj:1.5.2'
asciidoclet 'org.asciidoctor:asciidoclet:0.+' asciidoclet 'org.asciidoctor:asciidoclet:0.+'
jdocbookXsl "org.jboss.pressgang:pressgang-xslt-ns:${pressgangVersion}"
jdocbookXsl "org.jboss.pressgang:pressgang-fonts:${pressgangVersion}"
jdocbookStyles "org.jboss.pressgang:pressgang-jdocbook-style:${pressgangVersion}"
compile( libraries.jpa ) compile( libraries.jpa )
compile( project( ':hibernate-jpamodelgen' ) ) compile( project( ':hibernate-jpamodelgen' ) )
@ -230,51 +224,6 @@ task aggregateJavadocs(type: Javadoc) {
} }
} }
// jDocBook ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jdocbook {
// shared config
format('html_single') {
finalName = "index.html"
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml-single.xsl"
}
format('html') {
finalName = "index.html"
stylesheet = "classpath:/xslt/org/hibernate/jdocbook/xslt/xhtml.xsl"
}
// book-specific config
integrationsGuide {
masterSourceDocumentName = 'Hibernate_Integrations_Guide.xml'
}
mappingGuide {
masterSourceDocumentName = 'Hibernate_Mapping_Guide.xml'
}
}
[ 'integrationsGuide', 'mappingGuide'].each { bookName ->
task "stageLocalStyles_$bookName"(type: Copy) {
into project.file( "target/docbook/stage/$bookName" )
from project.file( 'src/main/style' )
includeEmptyDirs = false
}
tasks[ "stageStyles_$bookName" ].dependsOn "stageLocalStyles_$bookName"
tasks[ "stageStyles_$bookName" ].doLast {
logger.lifecycle( "Staging devguide-specific style resources")
copy {
into project.file( "target/docbook/stage/$bookName/images" )
from project.file( "src/main/docbook/$bookName/en-US" )
include '**/images/*.png'
include '**/images/*.svg'
includeEmptyDirs = false
}
}
}
asciidoctor { asciidoctor {
// we do not want it creating its "default task" // we do not want it creating its "default task"
enabled = false enabled = false
@ -341,11 +290,11 @@ task renderMappingGuide(type: AsciidoctorTask, group: 'Documentation') {
} }
} }
// User Guides ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final String[] versionComponents = version.split( '\\.' ); final String[] versionComponents = version.split( '\\.' );
final String majorMinorVersion = versionComponents[0] + '.' + versionComponents[1]; final String majorMinorVersion = versionComponents[0] + '.' + versionComponents[1];
// User Guide ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
task renderUserGuide(type: AsciidoctorTask, group: 'Documentation') { task renderUserGuide(type: AsciidoctorTask, group: 'Documentation') {
description = 'Renders the User Guides in HTML format using Asciidoctor.' description = 'Renders the User Guides in HTML format using Asciidoctor.'
sourceDir = file( 'src/main/asciidoc/userguide' ) sourceDir = file( 'src/main/asciidoc/userguide' )
@ -367,6 +316,28 @@ task renderUserGuide(type: AsciidoctorTask, group: 'Documentation') {
} }
} }
// Integration Guide ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
task renderIntegrationGuide(type: AsciidoctorTask, group: 'Documentation') {
description = 'Renders the User Guides in HTML format using Asciidoctor.'
sourceDir = file( 'src/main/asciidoc/integrationguide' )
outputDir = new File("$buildDir/asciidoc/integrationguide/html_single")
backends "html5"
separateOutputDirs false
options logDocuments: true
attributes icons: 'font', experimental: true, 'source-highlighter': 'prettify', linkcss: true, stylesheet: "css/hibernate.css", majorMinorVersion: majorMinorVersion
resources {
from('src/main/asciidoc/integrationguide/') {
include 'images/**'
}
from('src/main/style/asciidoctor') {
include 'images/**'
}
from('src/main/style/asciidoctor') {
include 'css/**'
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// grouping tasks // grouping tasks
@ -376,13 +347,10 @@ buildDocs.dependsOn aggregateJavadocs
buildDocs.dependsOn renderTopicalGuides buildDocs.dependsOn renderTopicalGuides
buildDocs.dependsOn renderGettingStartedGuides buildDocs.dependsOn renderGettingStartedGuides
buildDocs.dependsOn renderUserGuide buildDocs.dependsOn renderUserGuide
// the jDocBook plugin already adds its main task as a dependency of the buildDocs task buildDocs.dependsOn renderIntegrationGuide
buildDocsForPublishing.dependsOn aggregateJavadocs buildDocsForPublishing.dependsOn aggregateJavadocs
buildDocsForPublishing.dependsOn renderTopicalGuides buildDocsForPublishing.dependsOn renderTopicalGuides
buildDocsForPublishing.dependsOn renderGettingStartedGuides buildDocsForPublishing.dependsOn renderGettingStartedGuides
buildDocsForPublishing.dependsOn renderUserGuide buildDocsForPublishing.dependsOn renderUserGuide
// only html-single to match what Asciidoctor currently offers buildDocsForPublishing.dependsOn renderIntegrationGuide
//buildDocsForPublishing.dependsOn 'renderDocBook_integrationsGuide_en-US_html_single '
buildDocsForPublishing.dependsOn renderDocBook_integrationsGuide

View File

@ -0,0 +1,11 @@
= Hibernate ORM {majorMinorVersion} Integration Guide
Steve Ebersole, Vlad Mihalcea
:toc:
:toclevels: 3
include::Preface.adoc[]
:numbered:
include::chapters/services/Services.adoc[]

View File

@ -0,0 +1,13 @@
[[preface]]
== Preface
Hibernate is an http://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] solution for Java environments.
Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities.
It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC.
Hibernates design goal is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing using SQL and JDBC.
However, unlike many other persistence solutions, Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology and knowledge is as valid as always.
=== Audience
This guide is for software developers and architects who will be integrating Hibernate with Java EE application servers, Spring framework, caching solutions (e.g. Infinispan, Ehcache, Hazelcast).

View File

@ -0,0 +1,418 @@
[[services]]
== Services and Registries
:extrasdir: extras
Services and registries are new *as a formalized concept* starting in 4.0.
But the functionality provided by the different Services have actually been around in Hibernate much, much longer. What is new is managing them, their lifecycles and dependencies through a lightweight, dedicated container we call a `ServiceRegistry`.
The goal of this guide is to describe the design and purpose of these `Services` and `Registries`, as well as to look at details of their implementations where appropriate.
It will also delve into the ways third-party integrators and applications can leverage and customize `Services` and `Registries`.
[[services-service]]
=== What is a Service?
A services provides a certain types of functionality, in a pluggable manner.
Specifically they are interfaces defining certain functionality and then implementations of those `Service` contract interfaces.
The interface is known as the `Service` role; the implementation class is known as the `Service` implementation.
The pluggability comes from the fact that the `Service` implementation adheres to contract defined by the interface of the `Service` role and that consumers of the `Service` program to the `Service` role, not the implementation.
Generally speaking, users can plug in alternate implementations of all standard `Service` roles (overriding); they can also define additional services beyond the base set of `Service` roles (extending).
Let's look at an example to better define what a `Service` is.
Hibernate needs to be able to access JDBC `Connections` to the database.
The way it obtains and releases these `Connections` is through the `ConnectionProvider` service.
The `Service` is defined by the interface (service role) `org.hibernate.engine.jdbc.connections.spi.ConnectionProvider` which declares methods for obtaining and releasing the `Connections`.
There are then multiple implementations of that `Service` contract, varying in how they actually manage the `Connections`.
Internally Hibernate always references `org.hibernate.engine.jdbc.connections.spi.ConnectionProvider` rather than specific implementations in consuming the `Service` (we will get to producing the `Service` later when we talk about registries).
Because of that fact, other `ConnectionProvider` `Service` implementations could easily be plugged in.
There is nothing revolutionary here; programming to interfaces is generally accepted as good programming practice.
What's interesting is the `ServiceRegistry` and the pluggable swapping of the different implementors.
[[services-contracts]]
==== `Service` contracts
The basic requirement for a `Service` is to implement the marker interface `org.hibernate.service.Service`.
Hibernate uses this internally for some basic type safety.
The `Service` can also implement a number of optional life-cycle related contracts:
`org.hibernate.service.spi.Startable`::
allows the `Service` impl to be notified that it is being started and about to be put into use.
`org.hibernate.service.spi.Stoppable`::
allows the `Service` impl to be notified that it is being stopped and will be removed from use.
`org.hibernate.service.spi.ServiceRegistryAwareService`::
allows the `Service` to be injected with a reference to the registry that is managing it. See <<services-dependencies>> for more details.
`org.hibernate.service.spi.Manageable`::
marks the `Service` as manageable in JMX provided the JMX integration is enabled. This feature is still incomplete.
Other::
The different registry implementations also understand additional optional contracts specific to that registry. For details, see the details for each registry in <<services-registry>>.
[[services-dependencies]]
==== `Service` dependencies
Services are allowed to declare dependencies on other services using either of two approaches.
`@org.hibernate.service.spi.InjectService`::
+
Any method on the `Service` implementation class accepting a single parameter and annotated with `@InjectService` is considered requesting injection of another service.
+
By default, the type of the method parameter is expected to be the `Service` role to be injected.
If the parameter type is different than the `Service` role, the serviceRole attribute of the `@InjectService` annotation should be used to explicitly name the role.
+
By default, injected services are considered required, that is the start up will fail if a named dependent `Service` is missing.
If the `Service` to be injected is optional, the required attribute of the `@InjectService` annotation should be declared as `false` (default is `true`).
`org.hibernate.service.spi.ServiceRegistryAwareService`::
+
The second approach is a pull approach where the `Service` implements the optional `Service` interface `org.hibernate.service.spi.ServiceRegistryAwareService` which declares a single `injectServices` method.
+
During startup, Hibernate will inject the `org.hibernate.service.ServiceRegistry` itself into services which implement this interface.
The `Service` can then use the `ServiceRegistry` reference to locate any additional services it needs.
[[services-registry]]
=== What is a `ServiceRegistry`?
A `ServiceRegistry`, at its most basic, hosts and manages Services.
Its contract is defined by the `org.hibernate.service.ServiceRegistry` interface.
We already gave a basic overview and definition of services.
But services have other interesting characteristics as well:
* Services have a lifecycle.
* They have a scope.
* Services might depend on other services.
* They need to be produced (choose using one implementation over another).
The `ServiceRegistry` fulfills all these needs.
In a concise definition, the `ServiceRegistry` acts as a https://en.wikipedia.org/wiki/Inversion_of_control[Inversion-of-control (IoC)] container.
Why not just use an existing IoC framework?
The main reason was that this had to be as light-weight and as small of a footprint as possible.
The initial design also had called for `Services` to be swappable at runtime, which unfortunately had to be removed due to performance problems in the proxy-based swapping-solution; the plan is to investigate alternate ways to achieve swap-ability with better performance at a later date.
A `Service` is associated with a `ServiceRegistry`.
The `ServiceRegistry` scopes the `Service`.
The `ServiceRegistry` manages the lifecycle of the `Service`.
The `ServiceRegistry` handles injecting dependencies into the `Service` (actually both a pull and a push/injection approach are supported).
`ServiceRegistries` are also hierarchical, meaning a `ServiceRegistry` can have a parent `ServiceRegistry`.
Services in one registry can depend on and utilize services in that same registry as well as any parent registries.
[[services-binding]]
=== ServiceBinding
The association of a given `Service` to a given `ServiceRegistry` is called a binding and is represented by the `org.hibernate.service.spi.ServiceBinding` interface.
Furthermore, the specific contract between a ServiceBinding and the `ServiceRegistry` is represented by the `org.hibernate.service.spi.ServiceBinding.ServiceLifecycleOwner` interface.
There are two ways a `Service` becomes associated (bound) to a `ServiceRegistry`.
* the `Service` can be directly instantiated and then handed to the `ServiceRegistry`
* a `ServiceInitiator` can be given to the `ServiceRegistry` (which the `ServiceRegistry` will use if and when the `Service` is needed)
`ServiceRegistry` implementations register bindings through calls to the overloaded `org.hibernate.service.internal.AbstractServiceRegistryImpl#createServiceBinding` method accepting either a `Service` instance or a `ServiceInitiator` instance.
Each specific type of registry defines its own `ServiceInitiator` specialization.
[[services-registry-types]]
=== Types of ServiceRegistries
Currently Hibernate utilizes three different `ServiceRegistry` implementations forming a hierarchy.
Each type is a specialization for the purpose of type-safety, but they add no new functionality.
[[services-registry-boot]]
==== `BootstrapServiceRegistry`
The `org.hibernate.boot.registry.BootstrapServiceRegistry` holds three `Service` and is normally built by means of the `org.hibernate.boot.registry.BootstrapServiceRegistryBuilder` factory class.
The builder gives type safe access to customizing these three `Services`.
[IMPORTANT]
====
This registry holds services that absolutely have to be available for most things in Hibernate to work.
====
In normal usage, the `BootstrapServiceRegistry` has no parent.
The services of the `BootstrapServiceRegistry` cannot be extended (added to) nor overridden (replaced).
===== `ClassLoaderService`
The `Service` role for this `Service` is `org.hibernate.boot.registry.classloading.spi.ClassLoaderService`.
This `Service` defines Hibernate's ability to interact with `ClassLoaders`.
The manner in which Hibernate (or any library) should interact with `ClassLoaders` varies based on the runtime environment which is hosting the application.
Application servers, OSGi containers, and other modular class loading systems impose very specific class-loading requirements.
This `Service` provides Hibernate an abstraction from this environmental complexity.
And just as important, it does so in a centralized, swappable manner.
The specific capabilities exposed on this `Service` include:
* Locating `Class` references by name. This includes application classes as well as _integration_ classes.
* Locating resources (properties files, xml files, etc) as _classpath resources_
* Interacting with `java.util.ServiceLoader`, Java's own `Service` provider discovery mechanism
===== `IntegratorService`
The `Service` role for this `Service` is `org.hibernate.integrator.spi.IntegratorService.`
Applications, third-party integrators and others all need to integrate with Hibernate. Historically this used to require something (usually the application) to coordinate registering the pieces of each integration needed on behalf of each integration. The `org.hibernate.integrator.spi.Integrator` contract formalized this "integration SPI". The IntegratorService manages all known integrators.
[TIP]
====
The concept of "Integrator" is still being actively defined and developed. Expect changes in these SPIs.
====
There are two ways an integrator becomes known.
* The integrator may be manually registered by calling `BootstrapServiceRegistryBuilder#with(Integrator)`
* The integrator may be discovered, leveraging the standard Java `ServiceLoader` capability provided by the `ClassLoaderService`.
`Integrators` would simply define a file named `/META-INF/services/org.hibernate.integrator.spi.Integrator` and make it available on the classpath.
`ServiceLoader` covers the format of this file in detail, but essentially it lists classes by fully-qualified name that implement `Integrator` one per line.
===== `StrategySelector`
The `Service` role for this `Service` is `org.hibernate.boot.registry.selector.spi.StrategySelector`.
Think of this as the _short naming_ service.
Historically to configure Hibernate users would often need to give fully-qualified name references to internal Hibernate classes.
Of course, this has caused lots of problems as we refactor internal code and move these classes around into different package structures.
Enter the concept of short-naming, using a well defined and well known _short name_ for the strategy/implementation class.
The short name mappings in this `Service` can be managed, even by applications and integrators which can be very powerful.
For more information on this aspect, see:
* `BootstrapServiceRegistryBuilder#applyStrategySelector`
* `BootstrapServiceRegistryBuilder#applyStrategySelectors`
* `org.hibernate.boot.registry.selector.StrategyRegistrationProvider` via `ServiceLoader` discovery
* `StrategySelector#registerStrategyImplementor` / `StrategySelector#unRegisterStrategyImplementor`
[[services-registry-standard]]
==== `StandardServiceRegistry`
The `org.hibernate.boot.registry.StandardServiceRegistry` defines the main Hibernate `ServiceRegistry`, building on the `BootstrapServiceRegistry` which is its parent.
This registry is generally built using the `org.hibernate.boot.registry.StandardServiceRegistryBuilder` class.
By default, it holds most of the `Services` used by Hibernate.
For the full list of `Services` typically held in the `StandardServiceRegistry`, see the source code of `org.hibernate.service.StandardServiceInitiators`.
In normal usage, the parent of the StandardServiceRegistry is the BootstrapServiceRegistry.
The services of the StandardServiceRegistry can be extended (added to) and overridden (replaced).
===== `ConnectionProvider/MultiTenantConnectionProvider`
The `Service` providing Hibernate with `Connections` as needed.
Comes in two distinct (and mutually exclusive) roles:
`org.hibernate.engine.jdbc.connections.spi.ConnectionProvider`::
provides `Connections` in normal environments
`org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider`::
provides (tenant-specific) `Connections` in multi-tenant environments
===== `JdbcServices`
`org.hibernate.engine.jdbc.spi.JdbcServices` is an aggregator `Service` (a `Service` that aggregates other Services) exposing unified functionality around JDBC accessibility.
===== `TransactionCoordinatorBuilder`
`org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder` is used by Hibernate to integrate with and underlying transaction system.
It is responsible for building `org.hibernate.resource.transaction.spi.TransactionCoordinator` instances for use by each Hibernate `Session`.
===== `JtaPlatform`
When using a JTA-based `TransactionCoordinatorBuilder`, the `org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform` `Service` provides Hibernate access to the JTA `TransactionManager` and `UserTransaction`, as well handling `Synchronization` registration.
===== `JndiService`
The `org.hibernate.engine.jndi.spi.JndiService` `Service` is used by Hibernate to interact with JNDI contexts.
Hibernate's default `JndiService` assumes just a single `InitialContext`.
===== `RegionFactory`
The `org.hibernate.cache.spi.RegionFactory` `Service` defines the integration with third party cache implementors as second-level caching providers.
===== `SessionFactoryServiceRegistryFactory`
`org.hibernate.service.spi.SessionFactoryServiceRegistryFactory` is a `Service` that acts as a factory for building the third type of `ServiceRegistry` (the SessionFactoryServiceRegistry) which we will discuss next.
I opted for the _factory as service_ approach because in the current design there is really not a good exposed hook-in spot for when the `SessionFactoryServiceRegistry` needs to be built.
[[services-registry-sf]]
==== `SessionFactoryServiceRegistry`
`org.hibernate.service.spi.SessionFactoryServiceRegistry` is the third standard Hibernate `ServiceRegistry`.
`SessionFactoryServiceRegistry` is designed to hold `Services` which need access to the `SessionFactory`.
Typically its parent registry is the `StandardServiceRegistry`.
[NOTE]
====
Integrators, as it stands in 4.x, operate on the `SessionFactoryServiceRegistry`.
====
Currently `SessionFactoryServiceRegistry` holds just four Services.
===== `EventListenerRegistry`
`org.hibernate.event.service.spi.EventListenerRegistry` is the main `Service` managed in the `SessionFactoryServiceRegistry`.
The is the `Service` that manages all of Hibernate's event listeners.
A major use-case for `Integrators` is to alter the listener registry.
If doing custom listener registration, it is important to understand the `org.hibernate.event.service.spi.DuplicationStrategy` and its effect on registration.
The basic idea is to tell Hibernate:
* what makes a listener a duplicate
* how to handle duplicate registrations (error, first wins, last wins)
===== `StatisticsImplementor`
`org.hibernate.stat.spi.StatisticsImplementor` is the SPI portion of the Statistics API; the collector portion, if you will.
===== `NativeQueryInterpreter`
`org.hibernate.engine.query.spi.NativeQueryInterpreter` is the `Service` Hibernate uses for interpreting native queries.
Exists as a `Service` mainly so that integrations such as OGM can override it.
===== `CacheImplementor`
`org.hibernate.engine.spi.CacheImplementor` provides a way to customize the way Hibernate interacts with the second-level caching implementation.
[[services-custom]]
=== Custom Services
So far we have focused on the Hibernate provided services.
But applications and integrations can provide their own services as well, either
* providing a new implementation of a standard `Service` (overriding)
* providing a whole new `Service` role (extending)
[[services-overriding]]
==== Custom `Service` Implementations (overriding)
We discussed swappability of `Service` implementations above.
Lets look at an example in practice.
For the sake of illustration, lets say that we have developed a new `ConnectionProvider` integrating with the wonderful new latest-and-greatest connection pooling library. Let's look at the steps necessary to make that happen.
The first step is to develop the actual integration by implementing the `ConnectionProvider` contract.
[[services-overriding-custom-ConnectionProvider-example]]
.Custom `ConnectionProvider` implementation
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/LatestAndGreatestConnectionProviderImpl.java[]
----
====
At this point we have a decision about how to integrate this new `ConnectionProvider` into Hibernate.
As you might guess, there are multiple ways.
As a first option, we might just require that the code bootstrapping the `StandardServiceRegistry` do the integration.
[[services-overriding-override-via-StandardServiceRegistryBuilder-example]]
.Overriding service implementation via `StandardServiceRegistryBuilder`
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/ex1-direct.java[]
----
====
A second option, if our `LatestAndGreatestConnectionProviderImpl` should always be used, would be to provide a `org.hibernate.service.spi.ServiceContributor` implementation as well to handle the integration on the users behalf.
[[services-LatestAndGreatestConnectionProviderImplContributor-example]]
.`LatestAndGreatestConnectionProviderImplContributor`
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/ex2-contributor.java[]
----
====
We still need to be able to tell Hibernate to perform this integration for us.
To do that we leverage Java's `ServiceLoader`.
When building the `StandardServiceRegistry`, Hibernate will look for JDK `Service` providers of type `org.hibernate.service.spi.ServiceContributor` and automatically integrate them.
We discussed this behavior above. Here we'd define a classpath resource named `META-INF/services/org.hibernate.service.spi.ServiceContributor`.
This file will have just a single line naming our impl.
[[services-META-INF-example]]
.`META-INF/services/org.hibernate.service.spi.ServiceContributor`
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/ex2-meta-inf[]
----
====
A third option, if we simply want to make our `LatestAndGreatestConnectionProviderImpl` available as a configuration choice, we would again use a `ServiceContributor` but in a slightly different way.
[[services-LatestAndGreatestConnectionProviderImplContributor-variation-example]]
.`LatestAndGreatestConnectionProviderImplContributor` variation
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/ex3-contributor.java[]
----
====
That all allows the application to pick our `LatestAndGreatestConnectionProviderImpl` by a short-name.
[[services-custom-service-short-name-example]]
.Custom service short-name
====
[source, JAVA, indent=0]
----
include::{extrasdir}/override/ex3-app.java[]
----
====
[[services-extending]]
==== Custom `Service` Roles (extending)
We can also have the `ServiceRegistry` host custom services (completely new `Service` roles).
As an example, let's say our application publishes Hibernate events to a JMS Topic and that we want to leverage the Hibernate `ServiceRegistry` to host a `Service` representing our publishing of events.
So, we will expand the `ServiceRegistry` to host this completely new `Service` role for us and manage its lifecycle.
[[services-EventPublishingService-service-role-example]]
.The `EventPublishingService` service role
====
[source, JAVA, indent=0]
----
include::{extrasdir}/extend/EventPublishingService.java[]
----
====
[[services-EventPublishingService-implementation-example]]
.The `EventPublishingService` implementation
====
[source, JAVA, indent=0]
----
include::{extrasdir}/extend/EventPublishingServiceImpl.java[]
----
====
[[services-alternate-EventPublishingService-implementation-example]]
.An alternative `EventPublishingService` implementation
====
[source, JAVA, indent=0]
----
include::{extrasdir}/extend/DisabledEventPublishingServiceImpl.java[]
----
====
Because we have alternative implementations, it is a good idea to develop an initiator as well that can choose between them at runtime.
[[services-EventPublishingServiceInitiator-example]]
.The `EventPublishingServiceInitiator`
====
[source, JAVA, indent=0]
----
include::{extrasdir}/extend/EventPublishingServiceInitiator.java[]
----
====
We could have the application register the `EventPublishingServiceInitiator` with the `StandardServiceRegistryBuilder`, but it is much nicer to write a `ServiceContributor` to handle this for the application.
[[services-EventPublishingServiceContributor-example]]
.The `EventPublishingServiceContributor`
====
[source, JAVA, indent=0]
----
include::{extrasdir}/extend/EventPublishingServiceContributor.java[]
----
====

View File

@ -0,0 +1,12 @@
BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder()
// pass in org.hibernate.integrator.spi.Integrator instances which are not
// auto-discovered (for whatever reason) but which should be included
.with( anExplicitIntegrator )
// pass in a class-loader Hibernate should use to load application classes
.withApplicationClassLoader( anExplicitClassLoaderForApplicationClasses )
// pass in a class-loader Hibernate should use to load resources
.withResourceClassLoader( anExplicitClassLoaderForResources )
// see BootstrapServiceRegistryBuilder for rest of available methods
...
// finally, build the bootstrap registry with all the above options
.build();

View File

@ -0,0 +1,13 @@
public class DisabledEventPublishingServiceImpl implements EventPublishingService {
public static DisabledEventPublishingServiceImpl INSTANCE =
new DisabledEventPublishingServiceImpl();
private DisabledEventPublishingServiceImpl() {
}
@Override
public void publish(Event theEvent) {
// nothing to do...
}
}

View File

@ -0,0 +1,4 @@
public interface EventPublishingService extends Service {
public void publish(Event theEvent);
}

View File

@ -0,0 +1,13 @@
public class EventPublishingServiceContributor
implements ServiceContributor {
@Override
public void contribute(StandardServiceRegistryBuilder builder) {
builder.addinitiator( eventpublishingserviceinitiator.instance );
// if we wanted to allow other strategies (e.g. a jms
// queue publisher) we might also register short names
// here with the strategyselector. the initiator would
// then need to accept the strategy as a config setting
}
}

View File

@ -0,0 +1,58 @@
public class EventPublishingServiceImpl
implements EventPublishingService, Configurable, Startable, Stoppable,
ServiceRegistryAwareService {
private ServiceRegistryImplementor serviceRegistry;
private String jmsConnectionFactoryName;
private String destinationName;
private Connection jmsConnection;
private Session jmsSession;
private MessageProducer publisher;
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
public void configure(Map configurationValues) {
this.jmsConnectionFactoryName = configurationValues
.get( JMS_CONNECTION_FACTORY_NAME_SETTING );
this.destinationName = configurationValues
.get( JMS_DESTINATION_NAME_SETTING );
}
@Override
public void start() {
final JndiService jndiService = serviceRegistry
.getService( JndiService.class );
final ConnectionFactory jmsConnectionFactory = jndiService
.locate( jmsConnectionFactoryName );
this.jmsConnection = jmsConnectionFactory.createConnection();
this.jmsSession = jmsConnection.createSession(
true,
Session.AUTO_ACKNOWLEDGE
);
final Destination destination = jndiService.locate( destinationName );
this.publisher = jmsSession.createProducer( destination );
}
@Override
public void publish(Event theEvent) {
publisher.send( theEvent );
}
@Override
public void stop() {
publisher.close();
jmsSession.close();
jmsConnection.close();
}
}

View File

@ -0,0 +1,33 @@
public class EventPublishingServiceInitiator
implements StandardServiceInitiator<EventPublishingService> {
public static EventPublishingServiceInitiator INSTANCE =
new EventPublishingServiceInitiator();
public static final String ENABLE_PUBLISHING_SETTING =
"com.acme.EventPublishingService.enabled";
@Override
public Class<R> getServiceInitiated() {
return EventPublishingService.class;
}
@Override
public R initiateService(
Map configurationValues,
ServiceRegistryImplementor registry) {
final boolean enabled = extractBoolean(
configurationValues,
ENABLE_PUBLISHING_SETTING
);
if ( enabled ) {
return new EventPublishingServiceImpl();
}
else {
return DisabledEventPublishingServiceImpl.INSTANCE;
}
}
...
}

View File

@ -0,0 +1,59 @@
import java.lang.Override;
public class LatestAndGreatestConnectionProviderImpl
implements ConnectionProvider, Startable, Stoppable, Configurable {
private LatestAndGreatestPoolBuilder lagPoolBuilder;
private LatestAndGreatestPool lagPool;
private boolean available = false;
@Override
public void configure(Map configurationValues) {
// extract our config from the settings map
lagPoolBuilder = buildBuilder( configurationValues );
}
@Override
public void start() {
// start the underlying pool
lagPool = lagPoolBuilder.buildPool();
available = true;
}
@Override
public void stop() {
available = false;
// stop the underlying pool
lagPool.shutdown();
}
@Override
public Connection getConnection() throws SQLException {
if ( !available ) {
throwException(
"LatestAndGreatest ConnectionProvider not available for use" )
}
return lagPool.borrowConnection();
}
@Override
public void closeConnection(Connection conn) throws SQLException {
if ( !available ) {
warn(
"LatestAndGreatest ConnectionProvider not available for use" )
}
if ( conn == null ) {
return;
}
lagPool.releaseConnection( conn );
}
...
}

View File

@ -0,0 +1,7 @@
StandardServiceRegistryBuilder builder = ...;
...
builder.addService(
ConnectionProvider.class,
new LatestAndGreatestConnectionProviderImpl()
);
...

View File

@ -0,0 +1,11 @@
public class LatestAndGreatestConnectionProviderImplContributor1
implements ServiceContributor {
@Override
public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) {
serviceRegistryBuilder.addService(
ConnectionProvider.class,
new LatestAndGreatestConnectionProviderImpl()
);
}
}

View File

@ -0,0 +1 @@
fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor1

View File

@ -0,0 +1,4 @@
StandardServiceRegistryBuilder builder = ...;
...
builder.applySetting( "hibernate.connection.provider_class", "lag" );
...

View File

@ -0,0 +1,19 @@
public class LatestAndGreatestConnectionProviderImplContributor
implements ServiceContributor {
@Override
public void contribute(
standardserviceregistrybuilder serviceregistrybuilder) {
// here we will register a short-name for our service strategy
strategyselector selector = serviceregistrybuilder
.getbootstrapserviceregistry().
.getservice( strategyselector.class );
selector.registerstrategyimplementor(
connectionprovider.class,
"lag"
latestandgreatestconnectionproviderimpl.class
);
}
}

View File

@ -0,0 +1 @@
fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor2

View File

@ -0,0 +1,23 @@
public class MyIntegrator implements org.hibernate.integrator.spi.Integrator {
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// As you might expect, an EventListenerRegistry is the thing with which event listeners are registered It is a
// service so we look it up using the service registry
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
// If you wish to have custom determination and handling of "duplicate" listeners, you would have to add an
// implementation of the org.hibernate.event.service.spi.DuplicationStrategy contract like this
eventListenerRegistry.addDuplicationStrategy( myDuplicationStrategy );
// EventListenerRegistry defines 3 ways to register listeners:
// 1) This form overrides any existing registrations with
eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, myCompleteSetOfListeners );
// 2) This form adds the specified listener(s) to the beginning of the listener chain
eventListenerRegistry.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledFirst );
// 3) This form adds the specified listener(s) to the end of the listener chain
eventListenerRegistry.appendListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast );
}
}

View File

@ -1,60 +1,41 @@
[[preface]] [[preface]]
== Preface == Preface
Developing Object-Oriented software that deals with data from Relational Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming.
Databases can be cumbersome and resource consuming. Development costs Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases.
are significantly higher due to a paradigm mismatch between how data is Hibernate is an Object/Relational Mapping solution for Java environments.
represented in objects versus relational databases. Hibernate is an The term http://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] refers to the technique of mapping data from an object model representation to a relational data model representation (and visa versa).
Object/Relational Mapping (ORM) solution for Java environments. ORM
refers to the technique of mapping data between an object model
representation to a relational data model representation. See
http://en.wikipedia.org/wiki/Object-relational_mapping[Wikipedia] for a
good high-level discussion. Also, Martin Fowler's
http://martinfowler.com/bliki/OrmHate.html[OrmHate] article takes a look
at many of the mentioned mismatch problems.
Although having a strong background in SQL is not required to use Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities.
Hibernate, having a basic understanding of the concepts can help you It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC.
understand Hibernate more quickly and fully. An understanding of data Hibernates design goal is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing using SQL and JDBC.
modeling principles is especially important. Both However, unlike many other persistence solutions, Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology and knowledge is as valid as always.
http://www.agiledata.org/essays/dataModeling101.html and
http://en.wikipedia.org/wiki/Data_modeling are good starting points for
understanding these data modeling principles.
Understanding the basics of transactions and design patterns such as Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier.
"Unit of Work" <<Bibliography.adoc#PoEAA,PoEAA>> or "ApplicationTransaction" are important as well. However, Hibernate can certainly help you to remove or encapsulate vendor-specific SQL code and will help with the common task of result set translation from a tabular representation to a graph of objects.
These topics will be discussed in the documentation, but a prior
understanding will certainly help.
Hibernate not only takes care of the mapping from Java classes to === Get Involved
database tables (and from Java data types to SQL data types), but also
provides data query and retrieval facilities. It can significantly
reduce development time otherwise spent with manual data handling in SQL
and JDBC. Hibernates design goal is to relieve the developer from 95%
of common data persistence-related programming tasks by eliminating the
need for manual, hand-crafted data processing using SQL and JDBC.
However, unlike many other persistence solutions, Hibernate does not
hide the power of SQL from you and guarantees that your investment in
relational technology and knowledge is as valid as always.
Hibernate may not be the best solution for data-centric applications * Use Hibernate and report any bugs or issues you find. See http://hibernate.org/issuetracker[Issue Tracker] for details.
that only use stored procedures to implement the business logic in the * Try your hand at fixing some bugs or implementing enhancements. Again, see http://hibernate.org/issuetracker[Issue Tracker].
database, it is most useful with object-oriented domain models and * Engage with the community using mailing lists, forums, IRC, or other ways listed in the http://hibernate.org/community[Community section].
business logic in the Java-based middle-tier. However, Hibernate can * Help improve or translate this documentation. Contact us on the developer mailing list if you have interest.
certainly help you to remove or encapsulate vendor-specific SQL code and * Spread the word. Let the rest of your organization know about the benefits of Hibernate.
will help with the common task of result set translation from a tabular
representation to a graph of objects.
See http://hibernate.org/orm/contribute/ for information on getting === Getting Started Guide
involved.
New users may want to first look through the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/quickstart/html_single/[Hibernate Getting Started Guide] for basic information as well as tutorials.
There is also a series of http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/topical/html_single/[topical guides] providing deep dives into various topics.
[TIP] [NOTE]
==== ====
If you are just getting started with using Hibernate you may want to While having a strong background in SQL is not required to use Hibernate, it certainly helps a lot because it all boils down to SQL statements.
start with the Hibernate Getting Started Guide available from the Probably even more important is an understanding of data modeling principles.
http://hibernate.org/orm/documentation[documentation page]. It contains You might want to consider these resources as a good starting point:
quick-start style tutorials as well as lots of introductory information.
There is also a series of topical guides providing deep dives into * http://en.wikipedia.org/wiki/Data_modeling[Data Modeling Wikipedia definition]
various topics. * http://www.agiledata.org/essays/dataModeling101.html[Data Modeling 101]
Understanding the basics of transactions and design patterns such as _Unit of Work_ <<Bibliography.adoc#PoEAA,PoEAA>> or _Application Transaction_ are important as well.
These topics will be discussed in the documentation, but a prior understanding will certainly help.
==== ====

View File

@ -38,8 +38,8 @@ task assembleDocumentation(type: Task, dependsOn: [rootProject.project( 'documen
// Integrations Guide // Integrations Guide
copy { copy {
from "${rootProject.project( 'documentation' ).buildDir}/docbook/publish/integrationsGuide/en-US" from "${rootProject.project( 'documentation' ).buildDir}/asciidoc/integrationguide"
into "${documentationDir}/integrationsGuide" into "${documentationDir}/integrationguide"
} }
// Getting-started Guide // Getting-started Guide