HHH-6117 - Figure out best way to handle SessionFactoryObjectFactory dealing with JNDI

This commit is contained in:
Steve Ebersole 2011-04-24 12:03:00 -05:00
parent ff74ceaaa4
commit 1a40b0232f
12 changed files with 460 additions and 384 deletions

View File

@ -54,6 +54,8 @@ import org.hibernate.engine.loading.CollectionLoadContext;
import org.hibernate.engine.loading.EntityLoadContext;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.service.jdbc.dialect.internal.AbstractDialectResolver;
import org.hibernate.service.jndi.JndiException;
import org.hibernate.service.jndi.JndiNameException;
import org.hibernate.type.BasicType;
import org.hibernate.type.SerializationException;
import org.hibernate.type.Type;
@ -310,12 +312,8 @@ public interface CoreMessageLogger extends BasicLogger {
void factoryBoundToJndiName( String name );
@LogMessage( level = INFO )
@Message( value = "Factory name: %s", id = 95 )
void factoryName( String name );
@LogMessage( level = INFO )
@Message( value = "A factory was renamed from name: %s", id = 96 )
void factoryRenamedFromName( String name );
@Message( value = "A factory was renamed from [%s] to [%s] in JNDI", id = 96 )
void factoryJndiRename(String oldName, String newName);
@LogMessage( level = INFO )
@Message( value = "Unbound factory from JNDI name: %s", id = 97 )
@ -438,8 +436,8 @@ public interface CoreMessageLogger extends BasicLogger {
void indexes( Set keySet );
@LogMessage( level = WARN )
@Message( value = "InitialContext did not implement EventContext", id = 127 )
void initialContextDidNotImplementEventContext();
@Message( value = "Could not bind JNDI listener", id = 127 )
void couldNotBindJndiListener();
@LogMessage( level = WARN )
@Message( value = "InitialContext did not implement EventContext", id = 128 )
@ -464,7 +462,7 @@ public interface CoreMessageLogger extends BasicLogger {
@LogMessage( level = ERROR )
@Message( value = "Invalid JNDI name: %s", id = 135 )
void invalidJndiName( String name,
@Cause InvalidNameException e );
@Cause JndiNameException e );
@LogMessage( level = WARN )
@Message( value = "Inapropriate use of @OnDelete on entity, annotation ignored: %s", id = 136 )
@ -594,10 +592,6 @@ public interface CoreMessageLogger extends BasicLogger {
void noSessionFactoryWithJndiName( String sfJNDIName,
@Cause NameNotFoundException e );
@LogMessage( level = INFO )
@Message( value = "Not binding factory to JNDI, no JNDI name configured", id = 185 )
void notBindingFactoryToJndi();
@LogMessage( level = INFO )
@Message( value = "Optimistic lock failures: %s", id = 187 )
void optimisticLockFailures( long optimisticFailureCount );
@ -910,7 +904,7 @@ public interface CoreMessageLogger extends BasicLogger {
@LogMessage( level = WARN )
@Message( value = "Could not bind factory to JNDI", id = 277 )
void unableToBindFactoryToJndi( @Cause NamingException e );
void unableToBindFactoryToJndi( @Cause JndiException e );
@LogMessage( level = INFO )
@Message( value = "Could not bind value '%s' to parameter: %s; %s", id = 278 )
@ -1292,7 +1286,7 @@ public interface CoreMessageLogger extends BasicLogger {
@LogMessage( level = WARN )
@Message( value = "Could not unbind factory from JNDI", id = 374 )
void unableToUnbindFactoryFromJndi( @Cause NamingException e );
void unableToUnbindFactoryFromJndi( @Cause JndiException e );
@Message( value = "Could not update hi value in: %s", id = 375 )
Object unableToUpdateHiValue( String tableName );
@ -1311,10 +1305,6 @@ public interface CoreMessageLogger extends BasicLogger {
void unableToWriteCachedFile( String path,
String message );
@LogMessage( level = INFO )
@Message( value = "Unbinding factory from JNDI name: %s", id = 379 )
void unbindingFactoryFromJndiName( String name );
@LogMessage( level = WARN )
@Message( value = "Unexpected literal token type [%s] passed for numeric processing", id = 380 )
void unexpectedLiteralTokenType( int type );

View File

@ -121,6 +121,7 @@ import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jndi.spi.JndiService;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
@ -397,7 +398,7 @@ public final class SessionFactoryImpl
catch (Exception e) {
throw new AssertionFailure("Could not generate UUID");
}
SessionFactoryObjectFactory.addInstance(uuid, name, this, properties);
SessionFactoryRegistry.INSTANCE.addSessionFactory( uuid, name, this, serviceRegistry.getService( JndiService.class ) );
LOG.debugf("Instantiated session factory");
@ -709,28 +710,34 @@ public final class SessionFactoryImpl
return collectionRolesByEntityParticipant.get( entityName );
}
// from javax.naming.Referenceable
@Override
public Reference getReference() throws NamingException {
LOG.debugf( "Returning a Reference to the SessionFactory" );
// from javax.naming.Referenceable
LOG.debug( "Returning a Reference to the SessionFactory" );
return new Reference(
SessionFactoryImpl.class.getName(),
new StringRefAddr("uuid", uuid),
SessionFactoryObjectFactory.class.getName(),
null
SessionFactoryImpl.class.getName(),
new StringRefAddr("uuid", uuid),
SessionFactoryRegistry.ObjectFactoryImpl.class.getName(),
null
);
}
private Object readResolve() throws ObjectStreamException {
LOG.trace("Resolving serialized SessionFactory");
// look for the instance by uuid
Object result = SessionFactoryObjectFactory.getInstance(uuid);
if (result==null) {
Object result = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid );
if ( result == null ) {
// in case we were deserialized in a different JVM, look for an instance with the same name
// (alternatively we could do an actual JNDI lookup here....)
result = SessionFactoryObjectFactory.getNamedInstance(name);
if (result == null) throw new InvalidObjectException("Could not find a SessionFactory named: " + name);
result = SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( name );
if ( result == null ) {
throw new InvalidObjectException( "Could not find a SessionFactory [uuid=" + uuid + ",name=" + name + "]" );
}
LOG.debugf("Resolved SessionFactory by name");
} else LOG.debugf("Resolved SessionFactory by UID");
}
else {
LOG.debugf("Resolved SessionFactory by UUID");
}
return result;
}
@ -931,7 +938,9 @@ public final class SessionFactoryImpl
schemaExport.drop( false, true );
}
SessionFactoryObjectFactory.removeInstance(uuid, name, properties);
SessionFactoryRegistry.INSTANCE.removeSessionFactory(
uuid, name, serviceRegistry.getService( JndiService.class )
);
observer.sessionFactoryClosed( this );
serviceRegistry.destroy();
@ -1264,17 +1273,14 @@ public final class SessionFactoryImpl
* @throws ClassNotFoundException indicates problems reading back serial data stream
*/
static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException, ClassNotFoundException {
String uuid = ois.readUTF();
final String uuid = ois.readUTF();
boolean isNamed = ois.readBoolean();
String name = null;
if ( isNamed ) {
name = ois.readUTF();
}
Object result = SessionFactoryObjectFactory.getInstance( uuid );
final String name = isNamed ? ois.readUTF() : null;
Object result = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid );
if ( result == null ) {
LOG.trace("Could not locate session factory by uuid [" + uuid + "] during session deserialization; trying name");
if ( isNamed ) {
result = SessionFactoryObjectFactory.getNamedInstance( name );
result = SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( name );
}
if ( result == null ) {
throw new InvalidObjectException( "could not resolve session factory during session deserialization [uuid=" + uuid + ", name=" + name + "]" );

View File

@ -1,168 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.event.EventContext;
import javax.naming.event.NamespaceChangeListener;
import javax.naming.event.NamingEvent;
import javax.naming.event.NamingExceptionEvent;
import javax.naming.event.NamingListener;
import javax.naming.spi.ObjectFactory;
import org.hibernate.SessionFactory;
import org.hibernate.internal.util.jndi.JndiHelper;
import org.jboss.logging.Logger;
/**
* Resolves {@link SessionFactory} instances during <tt>JNDI<tt> look-ups as well as during deserialization
*/
public class SessionFactoryObjectFactory implements ObjectFactory {
@SuppressWarnings({ "UnusedDeclaration" })
private static final SessionFactoryObjectFactory INSTANCE; //to stop the class from being unloaded
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,
SessionFactoryObjectFactory.class.getName());
static {
INSTANCE = new SessionFactoryObjectFactory();
LOG.debugf("Initializing class SessionFactoryObjectFactory");
}
private static final ConcurrentHashMap<String, SessionFactory> INSTANCES = new ConcurrentHashMap<String, SessionFactory>();
private static final ConcurrentHashMap<String, SessionFactory> NAMED_INSTANCES = new ConcurrentHashMap<String, SessionFactory>();
private static final NamingListener LISTENER = new NamespaceChangeListener() {
public void objectAdded(NamingEvent evt) {
LOG.debugf("A factory was successfully bound to name: %s", evt.getNewBinding().getName());
}
public void objectRemoved(NamingEvent evt) {
String name = evt.getOldBinding().getName();
LOG.factoryUnboundFromName(name);
Object instance = NAMED_INSTANCES.remove(name);
Iterator iter = INSTANCES.values().iterator();
while ( iter.hasNext() ) {
if ( iter.next()==instance ) iter.remove();
}
}
public void objectRenamed(NamingEvent evt) {
String name = evt.getOldBinding().getName();
LOG.factoryRenamedFromName(name);
NAMED_INSTANCES.put( evt.getNewBinding().getName(), NAMED_INSTANCES.remove(name) );
}
public void namingExceptionThrown(NamingExceptionEvent evt) {
//noinspection ThrowableResultOfMethodCallIgnored
LOG.namingExceptionAccessingFactory(evt.getException());
}
};
public Object getObjectInstance(Object reference, Name name, Context ctx, Hashtable env) throws Exception {
LOG.debugf("JNDI lookup: %s", name);
String uid = (String) ( (Reference) reference ).get(0).getContent();
return getInstance(uid);
}
public static void addInstance(String uid, String name, SessionFactory instance, Properties properties) {
LOG.debugf("Registered: %s (%s)", uid, name == null ? "<unnamed>" : name);
INSTANCES.put(uid, instance);
if (name!=null) NAMED_INSTANCES.put(name, instance);
//must add to JNDI _after_ adding to HashMaps, because some JNDI servers use serialization
if (name == null) LOG.notBindingFactoryToJndi();
else {
LOG.factoryName(name);
try {
Context ctx = JndiHelper.getInitialContext(properties);
JndiHelper.bind(ctx, name, instance);
LOG.factoryBoundToJndiName(name);
( (EventContext) ctx ).addNamingListener(name, EventContext.OBJECT_SCOPE, LISTENER);
}
catch (InvalidNameException ine) {
LOG.invalidJndiName(name, ine);
}
catch (NamingException ne) {
LOG.unableToBindFactoryToJndi(ne);
}
catch(ClassCastException cce) {
LOG.initialContextDidNotImplementEventContext();
}
}
}
public static void removeInstance(String uid, String name, Properties properties) {
//TODO: theoretically non-threadsafe...
if (name!=null) {
LOG.unbindingFactoryFromJndiName(name);
try {
Context ctx = JndiHelper.getInitialContext(properties);
ctx.unbind(name);
LOG.factoryUnboundFromJndiName(name);
}
catch (InvalidNameException ine) {
LOG.invalidJndiName(name, ine);
}
catch (NamingException ne) {
LOG.unableToUnbindFactoryFromJndi(ne);
}
NAMED_INSTANCES.remove(name);
}
INSTANCES.remove(uid);
}
public static Object getNamedInstance(String name) {
LOG.debugf("Lookup: name=%s", name);
Object result = NAMED_INSTANCES.get(name);
if (result==null) {
LOG.debugf("Not found: %s", name);
LOG.debugf(NAMED_INSTANCES.toString());
}
return result;
}
public static Object getInstance(String uid) {
LOG.debugf("Lookup: uid=%s", uid);
Object result = INSTANCES.get(uid);
if (result==null) {
LOG.debugf("Not found: %s", uid);
LOG.debugf(INSTANCES.toString());
}
return result;
}
}

View File

@ -0,0 +1,182 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.event.NamespaceChangeListener;
import javax.naming.event.NamingEvent;
import javax.naming.event.NamingExceptionEvent;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.service.jndi.JndiException;
import org.hibernate.service.jndi.JndiNameException;
import org.hibernate.service.jndi.spi.JndiService;
/**
* A registry of all {@link SessionFactory} instances for the same classloader as this class.
*
* This registry is used for serialization/deserialization as well as JNDI binding.
*
* @author Steve Ebersole
*/
public class SessionFactoryRegistry {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
SessionFactoryRegistry.class.getName()
);
public static final SessionFactoryRegistry INSTANCE = new SessionFactoryRegistry();
private final ConcurrentHashMap<String, SessionFactory> sessionFactoryMap = new ConcurrentHashMap<String, SessionFactory>();
private final ConcurrentHashMap<String,String> nameUuidXref = new ConcurrentHashMap<String, String>();
public SessionFactoryRegistry() {
LOG.debugf( "Initializing SessionFactoryRegistry : %s", this );
}
public void addSessionFactory(String uuid, String name, SessionFactory instance, JndiService jndiService) {
LOG.debugf( "Registering SessionFactory: %s (%s)", uuid, name == null ? "<unnamed>" : name );
sessionFactoryMap.put( uuid, instance );
if ( name == null ) {
LOG.debug( "Not binding factory to JNDI, no JNDI name configured" );
return;
}
nameUuidXref.put( name, uuid );
LOG.debugf( "SessionFactory name : %s, attempting to bind to JNDI", name );
try {
jndiService.bind( name, instance );
LOG.factoryBoundToJndiName( name );
try {
jndiService.addListener( name, LISTENER );
}
catch (Exception e) {
LOG.couldNotBindJndiListener();
}
}
catch (JndiNameException e) {
LOG.invalidJndiName( name, e );
}
catch (JndiException e) {
LOG.unableToBindFactoryToJndi( e );
}
}
public void removeSessionFactory(String uuid, String name, JndiService jndiService) {
if ( name != null ) {
try {
LOG.tracef( "Unbinding SessionFactory from JNDI : %s", name );
jndiService.unbind( name );
LOG.factoryUnboundFromJndiName( name );
}
catch ( JndiNameException e ) {
LOG.invalidJndiName( name, e );
}
catch ( JndiException e ) {
LOG.unableToUnbindFactoryFromJndi( e );
}
nameUuidXref.remove( name );
}
sessionFactoryMap.remove( uuid );
}
public SessionFactory getNamedSessionFactory(String name) {
LOG.debugf( "Lookup: name=%s", name );
final String uuid = nameUuidXref.get( name );
return getSessionFactory( uuid );
}
public SessionFactory getSessionFactory(String uuid) {
LOG.debugf( "Lookup: uid=%s", uuid );
final SessionFactory sessionFactory = sessionFactoryMap.get( uuid );
if ( sessionFactory == null ) {
LOG.debugf( "Not found: %s", uuid );
LOG.debugf( sessionFactoryMap.toString() );
}
return sessionFactory;
}
/**
* Implementation of {@literal JNDI} {@link javax.naming.event.NamespaceChangeListener} contract to listener for context events
* and react accordingly if necessary
*/
private final NamespaceChangeListener LISTENER = new NamespaceChangeListener() {
@Override
public void objectAdded(NamingEvent evt) {
LOG.debugf("A factory was successfully bound to name: %s", evt.getNewBinding().getName());
}
@Override
public void objectRemoved(NamingEvent evt) {
final String jndiName = evt.getOldBinding().getName();
LOG.factoryUnboundFromName( jndiName );
final String uuid = nameUuidXref.remove( jndiName );
if ( uuid == null ) {
// serious problem... but not sure what to do yet
}
sessionFactoryMap.remove( uuid );
}
@Override
public void objectRenamed(NamingEvent evt) {
final String oldJndiName = evt.getOldBinding().getName();
final String newJndiName = evt.getNewBinding().getName();
LOG.factoryJndiRename( oldJndiName, newJndiName );
final String uuid = nameUuidXref.remove( oldJndiName );
nameUuidXref.put( newJndiName, uuid );
}
@Override
public void namingExceptionThrown(NamingExceptionEvent evt) {
//noinspection ThrowableResultOfMethodCallIgnored
LOG.namingExceptionAccessingFactory(evt.getException());
}
};
public static class ObjectFactoryImpl implements ObjectFactory {
@Override
public Object getObjectInstance(Object reference, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
LOG.debugf( "JNDI lookup: %s", name );
final String uuid = (String) ( (Reference) reference ).get( 0 ).getContent();
LOG.tracef( "Resolved to UUID = %s", uuid );
return INSTANCE.getSessionFactory( uuid );
}
}
}

View File

@ -28,5 +28,6 @@
<p>
An internal package containing mostly implementations of central Hibernate APIs of the
{@link org.hibernate} package.
</p>
</body>
</html>

View File

@ -22,33 +22,35 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.util.jndi;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.cfg.Environment;
import org.jboss.logging.Logger;
/**
* Helper for dealing with JNDI.
*
* @deprecated As JNDI access should get routed through {@link org.hibernate.service.jndi.spi.JndiService}
*/
@Deprecated
public final class JndiHelper {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, JndiHelper.class.getName());
private JndiHelper() {
}
/**
* Given a hodge-podge of properties, extract out the ones relevant for JNDI interaction.
* Given a hodgepodge of properties, extract out the ones relevant for JNDI interaction.
*
* @param properties
* @return
* @param configurationValues The map of config values
*
* @return The extracted JNDI specific properties.
*/
@SuppressWarnings({ "unchecked" })
public static Properties extractJndiProperties(Map configurationValues) {
@ -83,116 +85,11 @@ public final class JndiHelper {
return jndiProperties;
}
/**
* Do a JNDI lookup. Mainly we are handling {@link NamingException}
*
* @param jndiName The namespace of the object to locate
* @param context The context in which to resolve the namespace.
*
* @return The located object; may be null.
*
* @throws JndiException if a {@link NamingException} occurs
*/
public static Object locate(String jndiName, Context context) {
try {
return context.lookup( jndiName );
}
catch ( NamingException e ) {
throw new JndiException( "Unable to lookup JNDI name [" + jndiName + "]", e );
}
}
/**
* Bind val to name in ctx, and make sure that all intermediate contexts exist.
*
* @param ctx the root context
* @param name the name as a string
* @param val the object to be bound
*
* @throws JndiException if a {@link NamingException} occurs
*/
public static void bind(String jndiName, Object value, Context context) {
try {
LOG.trace("Binding : " + jndiName);
context.rebind( jndiName, value );
}
catch ( Exception initialException ) {
// We had problems doing a simple bind operation. This could very well be caused by missing intermediate
// contexts, so we attempt to create those intermmediate contexts and bind again
Name n = tokenizeName( jndiName, context );
Context intermediateContextBase = context;
while ( n.size() > 1 ) {
final String intermediateContextName = n.get( 0 );
Context intermediateContext = null;
try {
LOG.trace("Intermediate lookup: " + intermediateContextName);
intermediateContext = (Context) intermediateContextBase.lookup( intermediateContextName );
}
catch ( NameNotFoundException handledBelow ) {
// ok as we will create it below if not found
}
catch ( NamingException e ) {
throw new JndiException( "Unaniticipated error doing intermediate lookup", e );
}
if (intermediateContext != null) LOG.trace("Found intermediate context: " + intermediateContextName);
else {
LOG.trace("Creating subcontext: " + intermediateContextName);
try {
intermediateContext = intermediateContextBase.createSubcontext( intermediateContextName );
}
catch ( NamingException e ) {
throw new JndiException( "Error creating intermediate context [" + intermediateContextName + "]", e );
}
}
intermediateContextBase = intermediateContext;
n = n.getSuffix( 1 );
}
LOG.trace("Binding : " + n);
try {
intermediateContextBase.rebind( n, value );
}
catch ( NamingException e ) {
throw new JndiException( "Error performing intermediate bind [" + n + "]", e );
}
}
LOG.debugf("Bound name: %s", jndiName);
}
private static Name tokenizeName(String jndiName, Context context) {
try {
return context.getNameParser( "" ).parse( jndiName );
}
catch ( NamingException e ) {
throw new JndiException( "Unable to tokenize JNDI name [" + jndiName + "]", e );
}
}
// todo : remove these once we get the services in place and integrated into the SessionFactory
public static InitialContext getInitialContext(Properties props) throws NamingException {
Hashtable hash = extractJndiProperties(props);
LOG.jndiInitialContextProperties(hash);
try {
return hash.size()==0 ?
new InitialContext() :
new InitialContext(hash);
}
catch (NamingException e) {
LOG.unableToObtainInitialContext(e);
throw e;
}
return hash.size()==0 ?
new InitialContext() :
new InitialContext(hash);
}
/**
@ -201,11 +98,11 @@ public final class JndiHelper {
* @param ctx the root context
* @param name the name as a string
* @param val the object to be bound
* @throws NamingException
*
* @throws NamingException Indicates a problem performing the bind.
*/
public static void bind(Context ctx, String name, Object val) throws NamingException {
try {
LOG.trace("Binding : " + name);
ctx.rebind(name, val);
}
catch (Exception e) {
@ -215,25 +112,21 @@ public final class JndiHelper {
Context subctx=null;
try {
LOG.trace("Lookup: " + ctxName);
subctx = (Context) ctx.lookup(ctxName);
}
catch (NameNotFoundException nfe) {}
catch (NameNotFoundException ignore) {
}
if (subctx!=null) {
LOG.debugf("Found subcontext: %s", ctxName);
ctx = subctx;
}
else {
LOG.creatingSubcontextInfo(ctxName);
ctx = ctx.createSubcontext(ctxName);
}
n = n.getSuffix(1);
}
LOG.trace("Binding : " + n);
ctx.rebind(n, val);
}
LOG.debugf("Bound name: %s", name);
}
}

View File

@ -47,9 +47,10 @@ import org.hibernate.TypeHelper;
import org.hibernate.engine.FilterDefinition;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
import org.hibernate.internal.SessionFactoryObjectFactory;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.service.jndi.internal.JndiServiceImpl;
import org.hibernate.stat.Statistics;
/**
@ -79,7 +80,7 @@ public class SessionFactoryStub implements SessionFactory {
throw new AssertionFailure("Could not generate UUID");
}
SessionFactoryObjectFactory.addInstance( uuid, name, this, service.getProperties() );
SessionFactoryRegistry.INSTANCE.addSessionFactory( uuid, name, this, new JndiServiceImpl( service.getProperties() ) );
}
@Override
@ -103,26 +104,32 @@ public class SessionFactoryStub implements SessionFactory {
//readResolveObject
private Object readResolve() throws ObjectStreamException {
// look for the instance by uuid
Object result = SessionFactoryObjectFactory.getInstance(uuid);
if (result==null) {
Object result = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid ) ;
if ( result == null ) {
// in case we were deserialized in a different JVM, look for an instance with the same name
// (alternatively we could do an actual JNDI lookup here....)
result = SessionFactoryObjectFactory.getNamedInstance(name);
if (result == null) throw new InvalidObjectException("Could not find a stub SessionFactory named: " + name);
result = SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( name );
if ( result == null ) {
throw new InvalidObjectException( "Could not find a SessionFactory [uuid=" + uuid + ",name=" + name + "]" );
}
LOG.debugf("Resolved stub SessionFactory by name");
} else LOG.debugf("Resolved stub SessionFactory by uid");
}
else {
LOG.debugf("Resolved stub SessionFactory by UUID");
}
return result;
}
/**
* @see javax.naming.Referenceable#getReference()
*/
@Override
public Reference getReference() throws NamingException {
return new Reference(
SessionFactoryStub.class.getName(),
new StringRefAddr("uuid", uuid),
SessionFactoryObjectFactory.class.getName(),
null
SessionFactoryStub.class.getName(),
new StringRefAddr("uuid", uuid),
SessionFactoryRegistry.ObjectFactoryImpl.class.getName(),
null
);
}

View File

@ -1,13 +1,15 @@
//$Id: StatisticsService.java 8262 2005-09-30 07:48:53Z oneovthafew $
package org.hibernate.jmx;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.Reference;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.internal.SessionFactoryObjectFactory;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.stat.EntityStatistics;
import org.hibernate.stat.QueryStatistics;
@ -15,8 +17,6 @@ import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics;
import org.hibernate.stat.internal.ConcurrentStatisticsImpl;
import org.jboss.logging.Logger;
/**
* JMX service for Hibernate statistics<br>
* <br>
@ -64,14 +64,16 @@ public class StatisticsService implements StatisticsServiceMBean {
public void setSessionFactoryJNDIName(String sfJNDIName) {
this.sfJNDIName = sfJNDIName;
try {
Object obj = new InitialContext().lookup(sfJNDIName);
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
setSessionFactory( (SessionFactory) SessionFactoryObjectFactory.getInstance( (String) ref.get(0).getContent() ) );
final SessionFactory sessionFactory;
final Object jndiValue = new InitialContext().lookup( sfJNDIName );
if ( jndiValue instanceof Reference ) {
final String uuid = (String) ( (Reference) jndiValue ).get( 0 ).getContent();
sessionFactory = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid );
}
else {
setSessionFactory( (SessionFactory) obj );
sessionFactory = (SessionFactory) jndiValue;
}
setSessionFactory( sessionFactory );
}
catch (NameNotFoundException e) {
LOG.noSessionFactoryWithJndiName(sfJNDIName, e);

View File

@ -21,7 +21,7 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.internal.util.jndi;
package org.hibernate.service.jndi;
import org.hibernate.HibernateException;
/**

View File

@ -0,0 +1,37 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jndi;
import org.hibernate.HibernateException;
/**
* Indicates a problem with a given JNDI name being deemed as not valid.
*
* @author Steve Ebersole
*/
public class JndiNameException extends HibernateException {
public JndiNameException(String string, Throwable root) {
super( string, root );
}
}

View File

@ -22,18 +22,26 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jndi.internal;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.event.EventContext;
import javax.naming.event.NamespaceChangeListener;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.jndi.JndiException;
import org.hibernate.internal.util.jndi.JndiHelper;
import org.hibernate.service.jndi.spi.JndiService;
import org.jboss.logging.Logger;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.jndi.JndiHelper;
import org.hibernate.service.jndi.JndiException;
import org.hibernate.service.jndi.JndiNameException;
import org.hibernate.service.jndi.spi.JndiService;
/**
* Standard implementation of JNDI services.
*
@ -52,16 +60,15 @@ public class JndiServiceImpl implements JndiService {
@Override
public Object locate(String jndiName) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
try {
return JndiHelper.locate( jndiName, initialContext );
return initialContext.lookup( name );
}
catch ( NamingException e ) {
throw new JndiException( "Unable to lookup JNDI name [" + jndiName + "]", e );
}
finally {
try {
initialContext.close();
}
catch ( NamingException e ) {
LOG.unableToCloseInitialContext(e.toString());
}
cleanUp( initialContext );
}
}
@ -74,19 +81,121 @@ public class JndiServiceImpl implements JndiService {
}
}
private Name parseName(String jndiName, Context context) {
try {
return context.getNameParser( "" ).parse( jndiName );
}
catch ( InvalidNameException e ) {
throw new JndiNameException( "JNDI name [" + jndiName + "] was not valid", e );
}
catch ( NamingException e ) {
throw new JndiException( "Error parsing JNDI name [" + jndiName + "]", e );
}
}
private void cleanUp(InitialContext initialContext) {
try {
initialContext.close();
}
catch ( NamingException e ) {
LOG.unableToCloseInitialContext(e.toString());
}
}
@Override
public void bind(String jndiName, Object value) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
try {
JndiHelper.bind( jndiName, value, initialContext );
bind( name, value, initialContext );
}
finally {
try {
initialContext.close();
}
catch ( NamingException e ) {
LOG.unableToCloseInitialContext(e.toString());
}
cleanUp( initialContext );
}
}
private void bind(Name name, Object value, Context context) {
try {
LOG.tracef( "Binding : %s", name );
context.rebind( name, value );
}
catch ( Exception initialException ) {
// We had problems doing a simple bind operation.
if ( name.size() == 1 ) {
// if the jndi name had only 1 component there is nothing more we can do...
throw new JndiException( "Error performing bind [" + name + "]", initialException );
}
// Otherwise, there is a good chance this may have been caused by missing intermediate contexts. So we
// attempt to create those missing intermediate contexts and bind again
Context intermediateContextBase = context;
while ( name.size() > 1 ) {
final String intermediateContextName = name.get( 0 );
Context intermediateContext = null;
try {
LOG.trace("Intermediate lookup: " + intermediateContextName);
intermediateContext = (Context) intermediateContextBase.lookup( intermediateContextName );
}
catch ( NameNotFoundException handledBelow ) {
// ok as we will create it below if not found
}
catch ( NamingException e ) {
throw new JndiException( "Unanticipated error doing intermediate lookup", e );
}
if (intermediateContext != null) LOG.trace("Found intermediate context: " + intermediateContextName);
else {
LOG.trace("Creating sub-context: " + intermediateContextName);
try {
intermediateContext = intermediateContextBase.createSubcontext( intermediateContextName );
}
catch ( NamingException e ) {
throw new JndiException( "Error creating intermediate context [" + intermediateContextName + "]", e );
}
}
intermediateContextBase = intermediateContext;
name = name.getSuffix( 1 );
}
LOG.trace("Binding : " + name);
try {
intermediateContextBase.rebind( name, value );
}
catch ( NamingException e ) {
throw new JndiException( "Error performing intermediate bind [" + name + "]", e );
}
}
LOG.debugf( "Bound name: %s", name );
}
@Override
public void unbind(String jndiName) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
try {
initialContext.unbind( name );
}
catch (Exception e) {
throw new JndiException( "Error performing unbind [" + name + "]", e );
}
finally {
cleanUp( initialContext );
}
}
@Override
public void addListener(String jndiName, NamespaceChangeListener listener) {
InitialContext initialContext = buildInitialContext();
Name name = parseName( jndiName, initialContext );
try {
( (EventContext) initialContext ).addNamingListener( name, EventContext.OBJECT_SCOPE, listener );
}
catch (Exception e) {
throw new JndiException( "Unable to bind listener to namespace [" + name + "]", e );
}
finally {
cleanUp( initialContext );
}
}
}

View File

@ -23,28 +23,45 @@
*/
package org.hibernate.service.jndi.spi;
import javax.naming.event.NamespaceChangeListener;
import org.hibernate.service.Service;
/**
* Service providing simplified access to JNDI related features needed by Hibernate.
* Service providing simplified access to {@literal JNDI} related features needed by Hibernate.
*
* @author Steve Ebersole
*/
public interface JndiService extends Service {
/**
* Locate an object in JNDI by name
* Locate an object in {@literal JNDI} by name
*
* @param jndiName The JNDI name of the object to locate
* @param jndiName The {@literal JNDI} name of the object to locate
*
* @return The object found (may be null).
*/
public Object locate(String jndiName);
/**
* Binds a value into JNDI by name.
* Binds a value into {@literal JNDI} by name.
*
* @param jndiName The name under whcih to bind the object
* @param jndiName The name under which to bind the object
* @param value The value to bind
*/
public void bind(String jndiName, Object value);
/**
* Unbind a value from {@literal JNDI} by name.
*
* @param jndiName The name under which the object is bound
*/
public void unbind(String jndiName);
/**
* Adds the specified listener to the given {@literal JNDI} namespace.
*
* @param jndiName The {@literal JNDI} namespace
* @param listener The listener
*/
public void addListener(String jndiName, NamespaceChangeListener listener);
}