HHH-6657 - Document org.hibernate.integrator.spi.IntegratorService
This commit is contained in:
parent
066fea02c7
commit
0481dad403
|
@ -935,7 +935,25 @@
|
|||
<section id="services-IntegratorService">
|
||||
<title><interfacename>org.hibernate.integrator.spi.IntegratorService</interfacename></title>
|
||||
<para>
|
||||
Coming soon... See <ulink url="https://hibernate.onjira.com/browse/HHH-6657" />
|
||||
Applications, add-ons and others all need to integrate with Hibernate which used to require
|
||||
something, usually the application, to coordinate registering the pieces of each integration
|
||||
needed onm behalf of each integrator. The intent of this service is to allow those integrators
|
||||
to be discovered and to have them integrate themselves with Hibernate.
|
||||
</para>
|
||||
<para>
|
||||
This service focuses on the discovery aspect. It leverages the Java
|
||||
<classname>java.util.ServiceLoader</classname> capability provided by the
|
||||
<interfacename>org.hibernate.service.classloading.spi.ClassLoaderService</interfacename>
|
||||
in order to discover implementations of the
|
||||
<interfacename>org.hibernate.integrator.spi.Integrator</interfacename> contract.
|
||||
Integrators would simply define a file named
|
||||
<filename>/META-INF/services/org.hibernate.integrator.spi.Integrator</filename> and make it
|
||||
available on the classpath. <classname>java.util.ServiceLoader</classname> covers the
|
||||
format of this file in detail, but essentially it list classes by FQN that implement the
|
||||
<interfacename>org.hibernate.integrator.spi.Integrator</interfacename> one per line.
|
||||
</para>
|
||||
<para>
|
||||
See <xref linkend="integrators"/>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
@ -993,4 +1011,42 @@
|
|||
</para>
|
||||
</section>
|
||||
|
||||
<section id="integrators">
|
||||
<title>Integrators</title>
|
||||
<para>
|
||||
The <interfacename>org.hibernate.integrator.spi.Integrator</interfacename> is intended to provide a simple
|
||||
means for allowing developers to hook into the process of building a functioning SessionFactory. The
|
||||
The <interfacename>org.hibernate.integrator.spi.Integrator</interfacename> interface defines 2 methods of
|
||||
interest: <methodname>integrate</methodname> allows us to hook into the building process;
|
||||
<methodname>disintegrate</methodname> allows us to hook into a SessionFactory shutting down.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
There is a 3rd method defined on <interfacename>org.hibernate.integrator.spi.Integrator</interfacename>,
|
||||
an overloaded form of <methodname>integrate</methodname> accepting a
|
||||
<interfacename>org.hibernate.metamodel.source.MetadataImplementor</interfacename> instead of
|
||||
<classname>org.hibernate.cfg.Configuration</classname>. This form is intended for use with the new
|
||||
metamodel code scheduled for completion in 5.0
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
See <xref linkend="services-IntegratorService"/>
|
||||
</para>
|
||||
|
||||
<section id="integrators-uses">
|
||||
<title>Integrator use-cases</title>
|
||||
<para>
|
||||
The main use cases for an <interfacename>org.hibernate.integrator.spi.Integrator</interfacename> right
|
||||
now are registering event listeners and providing services (see
|
||||
<interfacename>org.hibernate.integrator.spi.ServiceContributingIntegrator</interfacename>). With 5.0
|
||||
we plan on expanding that to allow altering the metamodel describing the mapping between object and
|
||||
relational models.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Registering event listeners</title>
|
||||
<programlisting><xi:include href="extras/register-event-listeners-example.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
|
||||
</example>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
|
@ -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.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast );
|
||||
}
|
||||
}
|
|
@ -171,15 +171,14 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
|
||||
<para>
|
||||
If you have to react to particular events in your persistence layer, you can
|
||||
also use the Hibernate3 <emphasis>event</emphasis> architecture. The event
|
||||
also use the Hibernate <emphasis>event</emphasis> architecture. The event
|
||||
system can be used in addition, or as a replacement, for interceptors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
All the methods of the <literal>Session</literal> interface correlate
|
||||
to an event. You have a <literal>LoadEvent</literal>, a <literal>FlushEvent</literal>, etc.
|
||||
Consult the XML configuration-file DTD or the <literal>org.hibernate.event</literal>
|
||||
package for the full list of defined event types. When a request is made of one of
|
||||
Many methods of the <literal>Session</literal> interface correlate to an event type. The
|
||||
full range of defined event types is declared as enum values on
|
||||
<classname>org.hibernate.event.spi.EventType</classname>. When a request is made of one of
|
||||
these methods, the Hibernate <literal>Session</literal> generates an appropriate
|
||||
event and passes it to the configured event listeners for that type. Out-of-the-box,
|
||||
these listeners implement the same processing in which those methods always resulted.
|
||||
|
@ -190,19 +189,23 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
made of the <literal>Session</literal>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
See the <citetitle pubwork="book">Hibernate Developer Guide</citetitle> for information on registering
|
||||
custom event listeners.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The listeners should be considered singletons. This means they are shared between
|
||||
requests, and should not save any state as instance variables.
|
||||
The listeners should be considered stateless; they are shared between requests, and should not save any
|
||||
state as instance variables.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A custom listener implements the appropriate interface for the event it wants to
|
||||
process and/or extend one of the convenience base classes (or even the default event
|
||||
listeners used by Hibernate out-of-the-box as these are declared non-final for this
|
||||
purpose). Custom listeners can either be registered programmatically through the
|
||||
<literal>Configuration</literal> object, or specified in the Hibernate configuration
|
||||
XML. Declarative configuration through the properties file is not supported. Here is an
|
||||
example of a custom load event listener:
|
||||
purpose). Here is an example of a custom load event listener:
|
||||
</para>
|
||||
|
||||
<programlisting role="JAVA"><![CDATA[public class MyLoadListener implements LoadEventListener {
|
||||
|
@ -215,80 +218,34 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
You also need a configuration entry telling Hibernate to use the listener in addition
|
||||
to the default listener:
|
||||
</para>
|
||||
|
||||
<programlisting role="XML"><![CDATA[<hibernate-configuration>
|
||||
<session-factory>
|
||||
...
|
||||
<event type="load">
|
||||
<listener class="com.eg.MyLoadListener"/>
|
||||
<listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
|
||||
</event>
|
||||
</session-factory>
|
||||
</hibernate-configuration>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Instead, you can register it programmatically:
|
||||
</para>
|
||||
|
||||
<programlisting role="JAVA"><![CDATA[Configuration cfg = new Configuration();
|
||||
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
|
||||
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
|
||||
|
||||
<para>
|
||||
Listeners registered declaratively cannot share instances. If the same class name is
|
||||
used in multiple <literal><listener/></literal> elements, each reference will
|
||||
result in a separate instance of that class. If you need to share
|
||||
listener instances between listener types you must use the programmatic registration
|
||||
approach.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Why implement an interface and define the specific type during configuration? A
|
||||
listener implementation could implement multiple event listener interfaces. Having the
|
||||
type additionally defined during registration makes it easier to turn custom listeners on
|
||||
or off during configuration.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="objectstate-decl-security" revision="2">
|
||||
<title>Hibernate declarative security</title>
|
||||
<para>
|
||||
Usually, declarative security in Hibernate applications is managed in a session facade
|
||||
layer. Hibernate3 allows certain actions to be permissioned via JACC, and authorized
|
||||
layer. Hibernate allows certain actions to be permissioned via JACC, and authorized
|
||||
via JAAS. This is an optional functionality that is built on top of the event architecture.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
First, you must configure the appropriate event listeners, to enable the use of JAAS
|
||||
authorization.
|
||||
</para>
|
||||
|
||||
<programlisting role="XML"><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.internal.JACCPreDeleteEventListener"/>
|
||||
<listener type="pre-update" class="org.hibernate.secure.internal.JACCPreUpdateEventListener"/>
|
||||
<listener type="pre-insert" class="org.hibernate.secure.internal.JACCPreInsertEventListener"/>
|
||||
<listener type="pre-load" class="org.hibernate.secure.internal.JACCPreLoadEventListener"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Note that <literal><listener type="..." class="..."/></literal> is shorthand
|
||||
for <literal><event type="..."><listener class="..."/></event></literal>
|
||||
when there is exactly one listener for a particular event type.
|
||||
First, you must configure the appropriate event listeners, to enable the use of JACC
|
||||
authorization. Again, see <citetitle pubwork="book">Hibernate Developer Guide</citetitle>
|
||||
for the details. Below is an example of an appropriate
|
||||
<interfacename>org.hibernate.integrator.spi.Integrator</interfacename> implementation for this purpose.
|
||||
</para>
|
||||
|
||||
<programlisting role="JAVA"><xi:include href="../extras/jacc-event-reg-example.java" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude" /></programlisting>
|
||||
|
||||
<para>
|
||||
Next, while still in <literal>hibernate.cfg.xml</literal>, bind the permissions to roles:
|
||||
You must also decide how to configure your JACC provider. One option is to tell Hibernate what permissions
|
||||
to bind to what roles and have it configure the JACC provider. This would be done in the
|
||||
<literal>hibernate.cfg.xml</literal> file.
|
||||
</para>
|
||||
|
||||
|
||||
<programlisting role="XML"><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
|
||||
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
The role names are the roles understood by your JACC provider.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import org.hibernate.event.service.spi.DuplicationStrategy;
|
||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||
import org.hibernate.integrator.spi.Integrator;
|
||||
import org.hibernate.secure.internal.JACCPreDeleteEventListener;
|
||||
import org.hibernate.secure.internal.JACCPreInsertEventListener;
|
||||
import org.hibernate.secure.internal.JACCPreLoadEventListener;
|
||||
import org.hibernate.secure.internal.JACCPreUpdateEventListener;
|
||||
import org.hibernate.secure.internal.JACCSecurityListener;
|
||||
|
||||
public class JaccEventListenerIntegrator implements Integrator {
|
||||
|
||||
private static final DuplicationStrategy JACC_DUPLICATION_STRATEGY = new DuplicationStrategy() {
|
||||
@Override
|
||||
public boolean areMatch(Object listener, Object original) {
|
||||
return listener.getClass().equals( original.getClass() ) &&
|
||||
JACCSecurityListener.class.isInstance( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action getAction() {
|
||||
return Action.KEEP_ORIGINAL;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( {"unchecked"})
|
||||
public void integrate(
|
||||
Configuration configuration,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryServiceRegistry serviceRegistry) {
|
||||
boolean isSecurityEnabled = configuration.getProperties().containsKey( AvailableSettings.JACC_ENABLED );
|
||||
if ( !isSecurityEnabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
|
||||
eventListenerRegistry.addDuplicationStrategy( JACC_DUPLICATION_STRATEGY );
|
||||
|
||||
final String jaccContextId = configuration.getProperty( Environment.JACC_CONTEXTID );
|
||||
eventListenerRegistry.prependListeners( EventType.PRE_DELETE, new JACCPreDeleteEventListener(jaccContextId) );
|
||||
eventListenerRegistry.prependListeners( EventType.PRE_INSERT, new JACCPreInsertEventListener(jaccContextId) );
|
||||
eventListenerRegistry.prependListeners( EventType.PRE_UPDATE, new JACCPreUpdateEventListener(jaccContextId) );
|
||||
eventListenerRegistry.prependListeners( EventType.PRE_LOAD, new JACCPreLoadEventListener(jaccContextId) );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue