blob: 0a5624e2b87c21c02c9ced6f921c7c648f394b17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 Oracle.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* Bob Nettleton (Oracle) - Initial Reference Implementation
******************************************************************************/
package org.eclipse.gemini.naming;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.PrivilegedExceptionAction;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NoInitialContextException;
import javax.naming.directory.DirContext;
import javax.naming.spi.InitialContextFactory;
class ServiceAwareContextFactory {
private static Logger logger = Logger.getLogger(ServiceAwareContextFactory.class.getName());
/* private constructor to disallow creation of this class */
private ServiceAwareContextFactory() {}
static Context createServiceAwareContextWrapper(InitialContextFactory factory, Context internalContext, FactoryManager manager) {
return (Context) Proxy.newProxyInstance(ServiceAwareContextFactory.class.getClassLoader(),
new Class[] {Context.class},
new DefaultServiceAwareInvocationHandler(factory, internalContext, manager));
}
static DirContext createServiceAwareDirContextWrapper(InitialContextFactory factory, DirContext internalContext, FactoryManager manager) {
return (DirContext) Proxy.newProxyInstance(ServiceAwareContextFactory.class.getClassLoader(),
new Class[] {DirContext.class},
new DefaultServiceAwareInvocationHandler(factory, internalContext, manager));
}
private static class DefaultServiceAwareInvocationHandler implements InvocationHandler {
private InitialContextFactory m_factory;
private Context m_context;
private final FactoryManager m_manager;
private boolean m_isOpen;
DefaultServiceAwareInvocationHandler(InitialContextFactory factory, Context context, FactoryManager manager) {
m_factory = factory;
m_context = context;
m_manager = manager;
m_isOpen = true;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
synchronized (this) {
synchronized (m_manager) {
try {
return invokeContextMethod(method, args);
}
catch (Exception exception) {
if(exception instanceof NamingException) {
throw (NamingException)exception;
}
logger.log(Level.FINE,
"Exception occurred during a doPrivileged call",
exception);
// if the cause was not a NamingException, wrap the
// cause in NamingException and throw back to caller
NamingException namingException = new NamingException("Exception occured during a Context method invocation");
namingException.setRootCause(exception);
throw namingException;
}
}
}
}
private Object invokeContextMethod(Method method, Object[] args) throws Throwable {
if (m_isOpen) {
if (isFactoryServiceActive()
|| method.getName().equals("close")) {
if (method.getName().equals("close")) {
m_isOpen = false;
}
return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
}
else {
return SecurityUtils.invokePrivilegedAction(new ObtainFactoryAndInvokeAction(method, args));
}
} else {
// if context is already closed, do not try to
// rebind the backing service
// simply forward the call to the underlying context implementation
return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
}
}
private Object obtainNewFactoryAndInvoke(Method method, Object[] args) throws NamingException, Throwable, NoInitialContextException {
// make copy of existing context's environment
Hashtable newContextEnvironment = new Hashtable();
if (m_context.getEnvironment() != null) {
newContextEnvironment.putAll(m_context
.getEnvironment());
}
// attempt to recreate the required factory and context
try {
InitialContextFactory newFactory = m_manager
.createInitialContextFactory(newContextEnvironment);
if (newFactory != null) {
m_factory = newFactory;
Context newInternalContext = m_factory
.getInitialContext(newContextEnvironment);
if (newInternalContext != null) {
m_context = newInternalContext;
return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
}
}
}
catch (NoInitialContextException noContextException) {
logger.log(Level.SEVERE,
"An exception occurred while attempting to rebind the JNDI Provider service for this Context",
noContextException);
}
// if no InitialContextFactory service can handle this request, throw exception
throw new NoInitialContextException(
"The service that created this JNDI Context is not available");
}
/**
* Query to see if the IntialContextFactory used
* to create this context is still active
*
* @return true if factory service is still active
* false if factory service is no longer active
*/
private boolean isFactoryServiceActive() {
if(m_factory instanceof BuilderSupportedInitialContextFactory) {
return m_manager.isFactoryServiceActive(((BuilderSupportedInitialContextFactory)m_factory).getBuilder());
} else {
return m_manager.isFactoryServiceActive(m_factory);
}
}
private class ObtainFactoryAndInvokeAction implements PrivilegedExceptionAction {
private final Method m_method;
private final Object[] m_args;
ObtainFactoryAndInvokeAction(Method method, Object[] args) {
m_method = method;
m_args = args;
}
public Object run() throws Exception {
try {
return obtainNewFactoryAndInvoke(m_method, m_args);
} catch (Throwable e) {
if(e instanceof NamingException) {
throw (NamingException)e;
}
NamingException namingException = new NamingException("Error while attempting to obtain factory service on behalf of Context");
namingException.setRootCause(e);
throw namingException;
}
}
}
}
}