HHH-10006 - Document configuration of JndiService;
HHH-10007 - Audit Services chapter in Integrations Guide
This commit is contained in:
parent
2036280fa0
commit
8f4c2d5182
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
<chapter xml:id="services"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<title>Services and Registries</title>
|
||||
|
@ -20,7 +21,7 @@
|
|||
applications can leverage and customize Services and Registries.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<section xml:id="services-service">
|
||||
<title>What is a Service?</title>
|
||||
|
||||
<para>
|
||||
|
@ -58,7 +59,7 @@
|
|||
practice. What's interesting is the ServiceRegistry and the pluggable swapping of the different implementors.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<section xml:id="services-contracts">
|
||||
<title>Service contracts</title>
|
||||
|
||||
<para>
|
||||
|
@ -190,7 +191,7 @@
|
|||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<section xml:id="services-binding">
|
||||
<title>ServiceBinding</title>
|
||||
|
||||
<para>
|
||||
|
@ -203,8 +204,16 @@
|
|||
<para>
|
||||
There are 2 ways a Service becomes associated (bound) to a ServiceRegistry.
|
||||
<itemizedlist>
|
||||
<listitem>the Service can be directly instantiated and then handed to the ServiceRegistry</listitem>
|
||||
<listitem>a ServiceInitiator can be given to the ServiceRegistry (which the ServiceRegistry will use if and when the Service is needed)</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
the Service can be directly instantiated and then handed to the ServiceRegistry
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
a ServiceInitiator can be given to the ServiceRegistry (which the ServiceRegistry will use if and when the Service is needed)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
ServiceRegistry implementations register bindings through calls to the overloaded
|
||||
<methodname>org.hibernate.service.internal.AbstractServiceRegistryImpl#createServiceBinding</methodname>
|
||||
|
@ -217,7 +226,7 @@
|
|||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<section xml:id="services-registry-types">
|
||||
<title>Types of ServiceRegistries</title>
|
||||
|
||||
<para>
|
||||
|
@ -225,7 +234,7 @@
|
|||
type is a specialization for the purpose of type-safety, but they add no new functionality.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<section xml:id="services-registry-boot">
|
||||
<title>BootstrapServiceRegistry</title>
|
||||
|
||||
<para>
|
||||
|
@ -268,9 +277,22 @@
|
|||
<para>
|
||||
The specific capabilities exposed on this service include:
|
||||
<itemizedlist>
|
||||
<listitem>Locating Class references by name. This includes application classes as well as "integration" classes.</listitem>
|
||||
<listitem>Locating resources (properties files, xml files, etc) as "classpath resources"</listitem>
|
||||
<listitem>Interacting with <classname>java.util.ServiceLoader</classname>, Java's own service provider discovery mechanism</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Locating Class references by name. This includes application classes as well as "integration" classes.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Locating resources (properties files, xml files, etc) as "classpath resources"
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Interacting with <classname>java.util.ServiceLoader</classname>, Java's own service
|
||||
provider discovery mechanism
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
@ -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:
|
||||
<itemizedlist>
|
||||
<listitem><methodname>BootstrapServiceRegistryBuilder#applyStrategySelector</methodname></listitem>
|
||||
<listitem><methodname>BootstrapServiceRegistryBuilder#applyStrategySelectors</methodname></listitem>
|
||||
<listitem>
|
||||
<interfacename>org.hibernate.boot.registry.selector.StrategyRegistrationProvider</interfacename>
|
||||
via ServiceLoader discovery
|
||||
<para>
|
||||
<methodname>BootstrapServiceRegistryBuilder#applyStrategySelector</methodname>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<methodname>BootstrapServiceRegistryBuilder#applyStrategySelectors</methodname>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<interfacename>org.hibernate.boot.registry.selector.StrategyRegistrationProvider</interfacename>
|
||||
via ServiceLoader discovery
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<methodname>StrategySelector#registerStrategyImplementor`</methodname> /
|
||||
<methodname>StrategySelector#unRegisterStrategyImplementor</methodname>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
@ -355,7 +389,7 @@
|
|||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<section xml:id="services-registry-standard">
|
||||
<title>StandardServiceRegistry</title>
|
||||
|
||||
<para>
|
||||
|
@ -383,12 +417,16 @@
|
|||
exclusive) roles:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<interfacename>org.hibernate.engine.jdbc.connections.spi.ConnectionProvider</interfacename> -
|
||||
provides Connections in normal environments
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<interfacename>org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider</interfacename> -
|
||||
provides (tenant-specific) Connections in multi-tenant environments
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
@ -453,7 +491,7 @@
|
|||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<section xml:id="services-registry-sf">
|
||||
<title>SessionFactoryServiceRegistry</title>
|
||||
|
||||
<para>
|
||||
|
@ -488,8 +526,8 @@
|
|||
<classname>org.hibernate.event.service.spi.DuplicationStrategy</classname> and its effect on
|
||||
registration. The basic idea is to tell Hibernate:
|
||||
<itemizedlist>
|
||||
<listitem>what makes a listener a duplicate</listitem>
|
||||
<listitem>how to handle duplicate registrations (error, first wins, last wins)</listitem>
|
||||
<listitem><para>what makes a listener a duplicate</para></listitem>
|
||||
<listitem><para>how to handle duplicate registrations (error, first wins, last wins)</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
@ -520,4 +558,126 @@
|
|||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="services-custom">
|
||||
<title>Custom Services</title>
|
||||
<para>
|
||||
So far we have focused on the Hibernate provided services. But applications and integrations
|
||||
can provide their own services as well, either
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>providing a new implementation of a standard service (overriding)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>providing a whole new service role (extending)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<section xml:id="services-overriding">
|
||||
<title>Custom Service Implementations (overriding)</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The first step is to develop the actual integration by implementing the ConnectionProvider contract.
|
||||
</para>
|
||||
<example>
|
||||
<title>Custom ConnectionProvider implementation</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/override/LatestAndGreatestConnectionProviderImpl.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
At this point we have a decision about how to integrate this new ConnectionProvider into Hibernate.
|
||||
As you might guess, there are multiple ways.
|
||||
</para>
|
||||
<para>
|
||||
As a first option, we might just require that the code bootstrapping the StandardServiceRegistry do
|
||||
the integration.
|
||||
</para>
|
||||
<example>
|
||||
<title>Overriding service implementation via StandardServiceRegistryBuilder</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/override/ex1-direct.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
A second option, if our LatestAndGreatestConnectionProviderImpl should always be used, would be to
|
||||
provide a <interfacename>org.hibernate.service.spi.ServiceContributor</interfacename> implementation
|
||||
as well to handle the integration on the users behalf.
|
||||
</para>
|
||||
<example>
|
||||
<title>LatestAndGreatestConnectionProviderImplContributor</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/override/ex2-contributor.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
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 <interfacename>org.hibernate.service.spi.ServiceContributor</interfacename>
|
||||
and automatically integrate them. We discussed this behavior above. Here we'd define a classpath
|
||||
resource named <filename>META-INF/services/org.hibernate.service.spi.ServiceContributor</filename>.
|
||||
This file will have just a single line naming our impl.
|
||||
</para>
|
||||
<example>
|
||||
<title>META-INF/services/org.hibernate.service.spi.ServiceContributor</title>
|
||||
<programlisting><xi:include href="extras/override/ex2-meta-inf" parse="text" /></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<example>
|
||||
<title>LatestAndGreatestConnectionProviderImplContributor</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/override/ex3-contributor.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
<para>
|
||||
That all allows the appication to pick our LatestAndGreatestConnectionProviderImpl by a short-name.
|
||||
</para>
|
||||
<example>
|
||||
<title>Custom service short-name</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/override/ex3-app.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section xml:id="services-extending">
|
||||
<title>Custom Service Roles (extending)</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>The EventPublishingService service role</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/extend/EventPublishingService.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>The EventPublishingService implementation</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/extend/EventPublishingServiceImpl.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>An alternative EventPublishingService implementation</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/extend/EventPublishingServiceImpl.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
Because we have alternative implementations, it is a good idea to develop an initiator as well
|
||||
that can choose between them at runtime.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>The EventPublishingServiceInitiator</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/extend/EventPublishingServiceInitiator.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
|
@ -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...
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
public interface EventPublishingService extends Service {
|
||||
public void publish(Event theEvent);
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
...
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
...
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
StandardServiceRegistryBuilder builder = ...;
|
||||
...
|
||||
builder.addService(
|
||||
ConnectionProvider.class,
|
||||
new LatestAndGreatestConnectionProviderImpl()
|
||||
);
|
||||
...
|
|
@ -0,0 +1,10 @@
|
|||
public class LatestAndGreatestConnectionProviderImplContributor1
|
||||
implements ServiceContributor {
|
||||
@Override
|
||||
public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) {
|
||||
serviceRegistryBuilder.addService(
|
||||
ConnectionProvider.class,
|
||||
new LatestAndGreatestConnectionProviderImpl()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor1
|
|
@ -0,0 +1,4 @@
|
|||
StandardServiceRegistryBuilder builder = ...;
|
||||
...
|
||||
builder.applySetting( "hibernate.connection.provider_class", "lag" );
|
||||
...
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
fully.qualified.package.LatestAndGreatestConnectionProviderImplContributor2
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||
~
|
||||
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
-->
|
||||
<chapter xml:id="JNDI.xml"
|
||||
xml:lang="en"
|
||||
xmlns="http://docbook.org/ns/docbook">
|
||||
<title>JNDI</title>
|
||||
|
||||
<para>
|
||||
Hibernate does optionally interact with JNDI on the applications behalf. Generally
|
||||
it does this when the application:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>has asked the SessionFactory be bound to JNDI</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>has specified a DataSource to use by JNDI name</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>is using JTA transactions and the JtaPlatform needs to do JNDI lookups for TM, UT, etc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
All of these JNDI calls route through a single service whose role is
|
||||
<interfacename>org.hibernate.engine.jndi.spi.JndiService</interfacename>. The standard JndiService
|
||||
accepts a number of configuration settings
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>hibernate.jndi.class</literal> - names the
|
||||
<interfacename>javax.naming.InitialContext</interfacename> implementation class to use. See
|
||||
<constant>javax.naming.Context#INITIAL_CONTEXT_FACTORY</constant>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>hibernate.jndi.url</literal> - names the JNDI InitialContext connection url. See
|
||||
<constant>javax.naming.Context.PROVIDER_URL</constant>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Any other settings prefixed with <literal>hibernate.jndi.</literal> will be collected
|
||||
and passed along to the JNDI provider.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</note>
|
||||
</chapter>
|
Loading…
Reference in New Issue