From 8f4c2d5182e2ed73701b5acde00ae2d9535b89d0 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 31 Jul 2015 09:21:59 -0500 Subject: [PATCH] HHH-10006 - Document configuration of JndiService; HHH-10007 - Audit Services chapter in Integrations Guide --- .../en-US/chapters/services/Services.xml | 210 +++++++++++++++--- .../DisabledEventPublishingServiceImpl.java | 11 + .../extras/extend/EventPublishingService.java | 3 + .../EventPublishingServiceContributor.java | 12 + .../extend/EventPublishingServiceImpl.java | 50 +++++ .../EventPublishingServiceInitiator.java | 22 ++ ...testAndGreatestConnectionProviderImpl.java | 55 +++++ .../services/extras/override/ex1-direct.java | 7 + .../extras/override/ex2-contributor.java | 10 + .../services/extras/override/ex2-meta-inf | 1 + .../services/extras/override/ex3-app.java | 4 + .../extras/override/ex3-contributor.java | 14 ++ .../services/extras/override/ex3-meta-inf | 1 + .../manual/en-US/chapters/jndi/JNDI.xml | 63 ++++++ 14 files changed, 438 insertions(+), 25 deletions(-) create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/DisabledEventPublishingServiceImpl.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingService.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceContributor.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceImpl.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceInitiator.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/LatestAndGreatestConnectionProviderImpl.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex1-direct.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-contributor.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-meta-inf create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-app.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-contributor.java create mode 100644 documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-meta-inf create mode 100644 documentation/src/main/docbook/manual/en-US/chapters/jndi/JNDI.xml diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/Services.xml b/documentation/src/main/docbook/integration/en-US/chapters/services/Services.xml index 384e40640a..0c9244be11 100644 --- a/documentation/src/main/docbook/integration/en-US/chapters/services/Services.xml +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/Services.xml @@ -6,7 +6,8 @@ ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the lgpl.txt file in the root directory or . --> - Services and Registries @@ -20,7 +21,7 @@ applications can leverage and customize Services and Registries. -
+
What is a Service? @@ -58,7 +59,7 @@ practice. What's interesting is the ServiceRegistry and the pluggable swapping of the different implementors. -
+
Service contracts @@ -190,7 +191,7 @@
-
+
ServiceBinding @@ -203,8 +204,16 @@ There are 2 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) + + + 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 @@ -217,7 +226,7 @@
-
+
Types of ServiceRegistries @@ -225,7 +234,7 @@ type is a specialization for the purpose of type-safety, but they add no new functionality. -
+
BootstrapServiceRegistry @@ -268,9 +277,22 @@ 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 + + + 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 + +
@@ -339,15 +361,27 @@ 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 + + BootstrapServiceRegistryBuilder#applyStrategySelector + - StrategySelector#registerStrategyImplementor` / - StrategySelector#unRegisterStrategyImplementor + + BootstrapServiceRegistryBuilder#applyStrategySelectors + + + + + org.hibernate.boot.registry.selector.StrategyRegistrationProvider + via ServiceLoader discovery + + + + + StrategySelector#registerStrategyImplementor` / + StrategySelector#unRegisterStrategyImplementor + @@ -355,7 +389,7 @@
-
+
StandardServiceRegistry @@ -383,12 +417,16 @@ exclusive) roles: - org.hibernate.engine.jdbc.connections.spi.ConnectionProvider - - provides Connections in normal environments + + 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 + + org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider - + provides (tenant-specific) Connections in multi-tenant environments + @@ -453,7 +491,7 @@
-
+
SessionFactoryServiceRegistry @@ -488,8 +526,8 @@ 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) + what makes a listener a duplicate + how to handle duplicate registrations (error, first wins, last wins)
@@ -520,4 +558,126 @@
+
+ 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) + + + + +
+ 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. + + + Custom ConnectionProvider implementation + + + + 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. + + + Overriding service implementation via StandardServiceRegistryBuilder + + + + 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. + + + LatestAndGreatestConnectionProviderImplContributor + + + + 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. + + + META-INF/services/org.hibernate.service.spi.ServiceContributor + + + + 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. + + + LatestAndGreatestConnectionProviderImplContributor + + + + That all allows the appication to pick our LatestAndGreatestConnectionProviderImpl by a short-name. + + + Custom service short-name + + +
+ +
+ 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. + + + + The EventPublishingService service role + + + + + The EventPublishingService implementation + + + + + An alternative EventPublishingService implementation + + + + + Because we have alternative implementations, it is a good idea to develop an initiator as well + that can choose between them at runtime. + + + + The EventPublishingServiceInitiator + + + + + 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. + +
+
\ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/DisabledEventPublishingServiceImpl.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/DisabledEventPublishingServiceImpl.java new file mode 100644 index 0000000000..f11b81d3bd --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/DisabledEventPublishingServiceImpl.java @@ -0,0 +1,11 @@ +public class DisabledEventPublishingServiceImpl implements EventPublishingService { + public static DisabledEventPublishingServiceImpl INSTANCE = new DisabledEventPublishingServiceImpl(); + + private DisabledEventPublishingServiceImpl() { + } + + @Override + public void publish(Event theEvent) { + // nothing to do... + } +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingService.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingService.java new file mode 100644 index 0000000000..b371271fce --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingService.java @@ -0,0 +1,3 @@ +public interface EventPublishingService extends Service { + public void publish(Event theEvent); +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceContributor.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceContributor.java new file mode 100644 index 0000000000..a20507156d --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceContributor.java @@ -0,0 +1,12 @@ +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 + } +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceImpl.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceImpl.java new file mode 100644 index 0000000000..10368dac08 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceImpl.java @@ -0,0 +1,50 @@ +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(); + } +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceInitiator.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceInitiator.java new file mode 100644 index 0000000000..70cd53278e --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/extend/EventPublishingServiceInitiator.java @@ -0,0 +1,22 @@ +public class EventPublishingServiceInitiator implements StandardServiceInitiator { + public static EventPublishingServiceInitiator INSTANCE = new EventPublishingServiceInitiator(); + public static final String ENABLE_PUBLISHING_SETTING = "com.acme.EventPublishingService.enabled"; + + @Override + public Class 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; + } + } + + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/LatestAndGreatestConnectionProviderImpl.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/LatestAndGreatestConnectionProviderImpl.java new file mode 100644 index 0000000000..6246363cef --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/LatestAndGreatestConnectionProviderImpl.java @@ -0,0 +1,55 @@ +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 = true; + + // 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 ); + } + + ... +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex1-direct.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex1-direct.java new file mode 100644 index 0000000000..ce48995a00 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex1-direct.java @@ -0,0 +1,7 @@ +StandardServiceRegistryBuilder builder = ...; +... +builder.addService( + ConnectionProvider.class, + new LatestAndGreatestConnectionProviderImpl() +); +... \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-contributor.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-contributor.java new file mode 100644 index 0000000000..546b67ac26 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-contributor.java @@ -0,0 +1,10 @@ +public class LatestAndGreatestConnectionProviderImplContributor1 + implements ServiceContributor { + @Override + public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) { + serviceRegistryBuilder.addService( + ConnectionProvider.class, + new LatestAndGreatestConnectionProviderImpl() + ); + } +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-meta-inf b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-meta-inf new file mode 100644 index 0000000000..daeaf7cf33 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex2-meta-inf @@ -0,0 +1 @@ +fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor1 \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-app.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-app.java new file mode 100644 index 0000000000..d7c9a7a285 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-app.java @@ -0,0 +1,4 @@ +StandardServiceRegistryBuilder builder = ...; +... +builder.applySetting( "hibernate.connection.provider_class", "lag" ); +... \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-contributor.java b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-contributor.java new file mode 100644 index 0000000000..555c15a45d --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-contributor.java @@ -0,0 +1,14 @@ +public class LatestAndGreatestConnectionProviderImplContributor1 + 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 + ); + } +} \ No newline at end of file diff --git a/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-meta-inf b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-meta-inf new file mode 100644 index 0000000000..554711e5c7 --- /dev/null +++ b/documentation/src/main/docbook/integration/en-US/chapters/services/extras/override/ex3-meta-inf @@ -0,0 +1 @@ +fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor2 \ No newline at end of file diff --git a/documentation/src/main/docbook/manual/en-US/chapters/jndi/JNDI.xml b/documentation/src/main/docbook/manual/en-US/chapters/jndi/JNDI.xml new file mode 100644 index 0000000000..90ae9768af --- /dev/null +++ b/documentation/src/main/docbook/manual/en-US/chapters/jndi/JNDI.xml @@ -0,0 +1,63 @@ + + + + JNDI + + + Hibernate does optionally interact with JNDI on the applications behalf. Generally + it does this when the application: + + + has asked the SessionFactory be bound to JNDI + + + has specified a DataSource to use by JNDI name + + + is using JTA transactions and the JtaPlatform needs to do JNDI lookups for TM, UT, etc + + + + + + All of these JNDI calls route through a single service whose role is + org.hibernate.engine.jndi.spi.JndiService. The standard JndiService + accepts a number of configuration settings + + + + hibernate.jndi.class - names the + javax.naming.InitialContext implementation class to use. See + javax.naming.Context#INITIAL_CONTEXT_FACTORY + + + + + hibernate.jndi.url - names the JNDI InitialContext connection url. See + javax.naming.Context.PROVIDER_URL + + + + + Any other settings prefixed with hibernate.jndi. will be collected + and passed along to the JNDI provider. + + + + + + + + The standard JndiService assumes that all JNDI calls are relative to the same InitialContext. If your + application uses multiple naming servers for whatever reason, you will need a custom JndiService + implementation to handle those details. + + + \ No newline at end of file