/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.security.plugins;
import java.beans.PropertyEditorManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.jacc.PolicyContext;
import org.jboss.logging.Logger;
import org.jboss.security.AuthenticationManager;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SecurityConstants;
import org.jboss.security.SecurityDomain;
import org.jboss.security.SecurityProxyFactory;
import org.jboss.security.auth.callback.CallbackHandlerPolicyContextHandler;
import org.jboss.security.auth.callback.JBossCallbackHandler;
import org.jboss.security.config.SecurityConfiguration;
import org.jboss.security.integration.JNDIBasedSecurityManagement;
import org.jboss.security.integration.SecurityConstantsBridge;
import org.jboss.security.jacc.SubjectPolicyContextHandler;
import org.jboss.security.propertyeditor.PrincipalEditor;
import org.jboss.security.propertyeditor.SecurityDomainEditor;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.util.CachePolicy;
import org.jboss.util.TimedCachePolicy;
/**
* This is a JMX service which manages JAAS based SecurityManagers.
* JAAS SecurityManagers are responsible for validating credentials
* associated with principals. The service defaults to the
* org.jboss.security.plugins.JaasSecurityManager implementation but
* this can be changed via the securityManagerClass property.
*
* @see JaasSecurityManager
* @see org.jboss.security.SubjectSecurityManager
*
* @author <a href="on@ibis.odessa.ua">Oleg Nitz</a>
* @author <a href="rickard@telkel.com">Rickard Oberg</a>
* @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>
* @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
* @version $Revision: 96172 $
*/
public class JaasSecurityManagerService
extends ServiceMBeanSupport
implements JaasSecurityManagerServiceMBean
{
private static final String SECURITY_MGR_PATH = "java:/jaas";
private static final String DEFAULT_CACHE_POLICY_PATH = "java:/timedCacheFactory";
/** The log4j interface */
private static Logger log;
/** The class that provides the security manager implementation */
private static String securityMgrClassName = "org.jboss.security.plugins.JaasSecurityManager";
/** The loaded securityMgrClassName */
private static Class securityMgrClass = JaasSecurityManager.class;
/** The JAAS CallbackHandler interface implementation to use */
private static String callbackHandlerClassName = "org.jboss.security.auth.callback.JBossCallbackHandler";
private static Class callbackHandlerClass = org.jboss.security.auth.callback.JBossCallbackHandler.class;
/** The location of the security credential cache policy. This is first treated
as a ObjectFactory location that is capable of returning CachePolicy instances
on a per security domain basis by appending a '/security-domain-name' string
to this name when looking up the CachePolicy for a domain. If this fails then
the location is treated as a single CachePolicy for all security domains.
*/
private static String cacheJndiName = DEFAULT_CACHE_POLICY_PATH;
private static int defaultCacheTimeout = 30*60;
private static int defaultCacheResolution = 60;
/** The class that provides the SecurityProxyFactory implementation */
private static String securityProxyFactoryClassName = "org.jboss.security.SubjectSecurityProxyFactory";
private static Class securityProxyFactoryClass = org.jboss.security.SubjectSecurityProxyFactory.class;
/** A mapping from security domain name to a SecurityDomainContext object */
private static ConcurrentHashMap securityDomainCtxMap = new ConcurrentHashMap();
private static NameParser parser;
/** A flag indicating if the SecurityAssociation.setServer should be called */
private boolean serverMode = true;
/** A flag indicating if the Deep Copy of Subject Sets should be enabled in the security managers */
private static boolean deepCopySubjectMode = false;
/** The default unauthenticated principal */
private static String defaultUnauthenticatedPrincipal = "Unauthenticated Principal";
/** Frequency of the thread cleaning the authentication cache of expired entries */
private static int defaultCacheFlushPeriod = 60*60;
private static JNDIBasedSecurityManagement securityManagement = SecurityConstantsBridge.getSecurityManagement();
static
{
// Get a log interface, required for some statics below
// can not use instance field inherited from ServiceMBeanSupport
log = Logger.getLogger(JaasSecurityManagerService.class);
}
/** The constructor does nothing as the security manager is created
on each lookup into java:/jaas/xxx. This is also why all variables
in this class are static.
*/
public JaasSecurityManagerService()
{
}
public boolean getServerMode()
{
return serverMode;
}
public void setServerMode(boolean mode)
{
this.serverMode = mode;
}
public String getSecurityManagerClassName()
{
return securityMgrClassName;
}
public void setSecurityManagerClassName(String className)
throws ClassNotFoundException, ClassCastException
{
securityMgrClassName = className;
ClassLoader loader = getContextClassLoader();
securityMgrClass = loader.loadClass(securityMgrClassName);
if( AuthenticationManager.class.isAssignableFrom(securityMgrClass) == false )
throw new ClassCastException(securityMgrClass+" does not implement "+AuthenticationManager.class);
}
public String getSecurityProxyFactoryClassName()
{
return securityProxyFactoryClassName;
}
public void setSecurityProxyFactoryClassName(String className)
throws ClassNotFoundException
{
securityProxyFactoryClassName = className;
ClassLoader loader = getContextClassLoader();
securityProxyFactoryClass = loader.loadClass(securityProxyFactoryClassName);
}
/** Get the default CallbackHandler implementation class name
*
* @return The fully qualified classname of the
*/
public String getCallbackHandlerClassName()
{
return JaasSecurityManagerService.callbackHandlerClassName;
}
/** Set the default CallbackHandler implementation class name
* @see javax.security.auth.callback.CallbackHandler
*/
public void setCallbackHandlerClassName(String className)
throws ClassNotFoundException
{
callbackHandlerClassName = className;
ClassLoader loader = getContextClassLoader();
callbackHandlerClass = loader.loadClass(callbackHandlerClassName);
}
/** Get the jndi name under which the authentication cache policy is found
*/
public String getAuthenticationCacheJndiName()
{
return cacheJndiName;
}
/** Set the jndi name under which the authentication cache policy is found
*/
public void setAuthenticationCacheJndiName(String jndiName)
{
cacheJndiName = jndiName;
}
/** Get the default timed cache policy timeout.
@return the default cache timeout in seconds.
*/
public int getDefaultCacheTimeout()
{
return defaultCacheTimeout;
}
/** Set the default timed cache policy timeout. This has no affect if the
AuthenticationCacheJndiName has been changed from the default value.
@param timeoutInSecs - the cache timeout in seconds.
*/
public void setDefaultCacheTimeout(int timeoutInSecs)
{
defaultCacheTimeout = timeoutInSecs;
SecurityConstantsBridge.defaultCacheTimeout = timeoutInSecs;
}
/** Get the default timed cache policy resolution.
*/
public int getDefaultCacheResolution()
{
return defaultCacheResolution;
}
/** Set the default timed cache policy resolution. This has no affect if the
AuthenticationCacheJndiName has been changed from the default value.
@param resInSecs - resolution of timeouts in seconds.
*/
public void setDefaultCacheResolution(int resInSecs)
{
defaultCacheResolution = resInSecs;
SecurityConstantsBridge.defaultCacheResolution = resInSecs;
}
/**
* @see JaasSecurityManagerServiceMBean#getDeepCopySubjectMode()
*/
public boolean getDeepCopySubjectMode()
{
return deepCopySubjectMode;
}
/**
* @see JaasSecurityManagerServiceMBean#getDeepCopySubjectMode()
*/
public void setDeepCopySubjectMode(boolean flag)
{
log.debug("setDeepCopySubjectMode="+flag);
deepCopySubjectMode = flag;
//Update the security managers if already present
if(securityDomainCtxMap.isEmpty() == false)
{
Iterator iter = securityDomainCtxMap.keySet().iterator();
while(iter.hasNext())
{
String securityDomainName = (String)iter.next();
SecurityDomainContext sdc = (SecurityDomainContext)securityDomainCtxMap.get(securityDomainName);
setDeepCopySubjectOption(sdc.securityMgr, flag);
}
}
SecurityConfiguration.setDeepCopySubjectMode(flag);
}
/** Set the indicated security domain cache timeout. This only has an
effect if the security domain is using the default jboss TimedCachePolicy
implementation.
@param securityDomain the name of the security domain cache
@param timeoutInSecs - the cache timeout in seconds.
@param resInSecs - resolution of timeouts in seconds.
*/
public void setCacheTimeout(String securityDomain, int timeoutInSecs, int resInSecs)
{
CachePolicy cache = getCachePolicy(securityDomain);
if( cache != null && cache instanceof TimedCachePolicy )
{
TimedCachePolicy tcp = (TimedCachePolicy) cache;
synchronized( tcp )
{
tcp.setDefaultLifetime(timeoutInSecs);
tcp.setResolution(resInSecs);
}
}
else
{
log.warn("Failed to find cache policy for securityDomain='"
+ securityDomain + "'");
}
//Set the CacheTimeOut on JNDIBasedSecurityManagement
JNDIBasedSecurityManagement.setCacheTimeout(securityDomain, timeoutInSecs, resInSecs);
}
/**
* Get the authentication cache flush period
* @return period in seconds
*/
public int getDefaultCacheFlushPeriod()
{
return defaultCacheFlushPeriod;
}
/**
* Set the authentication cache flush period
*
* @param flushPeriodInSecs
*/
public void setDefaultCacheFlushPeriod(int flushPeriodInSecs)
{
this.defaultCacheFlushPeriod = flushPeriodInSecs;
JNDIBasedSecurityManagement.setDefaultCacheFlushPeriod(flushPeriodInSecs);
}
/** flush the cache policy for the indicated security domain if one exists.
* @param securityDomain the name of the security domain cache
*/
public void flushAuthenticationCache(String securityDomain)
{
CachePolicy cache = getCachePolicy(securityDomain);
if( cache != null )
{
cache.flush();
}
else
{
log.warn("Failed to find cache policy for securityDomain='"
+ securityDomain + "'");
}
}
/** Flush a principal's authentication cache entry associated with the
* given securityDomain.
*
* @param securityDomain the name of the security domain cache
* @param user the principal of the user to flush
*/
public void flushAuthenticationCache(String securityDomain, Principal user)
{
CachePolicy cache = getCachePolicy(securityDomain);
if( cache != null )
{
cache.remove(user);
}
else
{
log.warn("Failed to find cache policy for securityDomain='"
+ securityDomain + "'");
}
}
/** Return the active principals in the indicated security domain auth cache.
* @param securityDomain the name of the security to lookup the cache for
* @return List<Principal> of active keys found in the auth cache if
* the cache exists and is accessible, null otherwise.
*/
public List getAuthenticationCachePrincipals(String securityDomain)
{
CachePolicy cache = getCachePolicy(securityDomain);
List validPrincipals = null;
if( cache instanceof TimedCachePolicy )
{
TimedCachePolicy tcache = (TimedCachePolicy) cache;
validPrincipals = tcache.getValidKeys();
}
return validPrincipals;
}
// Begin SecurityManagerMBean interface methods
public boolean isValid(String securityDomain, Principal principal, Object credential)
{
boolean isValid = false;
try
{
SecurityDomainContext sdc = lookupSecurityDomain(securityDomain);
isValid = sdc.getSecurityManager().isValid(principal, credential, null);
}
catch(NamingException e)
{
log.debug("isValid("+securityDomain+") failed", e);
}
return isValid;
}
public Principal getPrincipal(String securityDomain, Principal principal)
{
Principal realmPrincipal = null;
try
{
SecurityDomainContext sdc = lookupSecurityDomain(securityDomain);
realmPrincipal = sdc.getRealmMapping().getPrincipal(principal);
}
catch(NamingException e)
{
log.debug("getPrincipal("+securityDomain+") failed", e);
}
return realmPrincipal;
}
public boolean doesUserHaveRole(String securityDomain, Principal principal,
Object credential, Set roles)
{
boolean doesUserHaveRole = false;
try
{
SecurityDomainContext sdc = lookupSecurityDomain(securityDomain);
// Must first validate the user
Subject subject = new Subject();
boolean isValid = sdc.getSecurityManager().isValid(principal, credential, subject);
if( isValid )
{
// Now can query if the authenticated Subject has the role
SubjectActions.pushSubjectContext(principal, credential, subject,
sdc.getSecurityManager().getSecurityDomain());
doesUserHaveRole = sdc.getRealmMapping().doesUserHaveRole(principal, roles);
SubjectActions.popSubjectContext();
}
}
catch(NamingException e)
{
log.debug("doesUserHaveRole("+securityDomain+") failed", e);
}
return doesUserHaveRole;
}
public Set getUserRoles(String securityDomain, Principal principal, Object credential)
{
Set userRoles = null;
try
{
SecurityDomainContext sdc = lookupSecurityDomain(securityDomain);
// Must first validate the user
Subject subject = new Subject();
boolean isValid = sdc.getSecurityManager().isValid(principal, credential, subject);
// Now can query if the authenticated Subject has the role
if( isValid )
{
SubjectActions.pushSubjectContext(principal, credential, subject,
sdc.getSecurityManager().getSecurityDomain() );
userRoles = sdc.getRealmMapping().getUserRoles(principal);
SubjectActions.popSubjectContext();
}
}
catch(NamingException e)
{
log.debug("getUserRoles("+securityDomain+") failed", e);
}
return userRoles;
}
// End SecurityManagerMBean interface methods
protected void startService() throws Exception
{
// use thread-local principal and credential propagation
if (serverMode)
SecurityAssociation.setServer();
// Register the default active Subject PolicyContextHandler
SubjectPolicyContextHandler handler = new SubjectPolicyContextHandler();
PolicyContext.registerHandler(SecurityConstants.SUBJECT_CONTEXT_KEY,
handler, true);
// Register the JAAS CallbackHandler JACC PolicyContextHandlers
CallbackHandlerPolicyContextHandler chandler = new CallbackHandlerPolicyContextHandler();
PolicyContext.registerHandler(CallbackHandlerPolicyContextHandler.CALLBACK_HANDLER_KEY,
chandler, true);
Context ctx = new InitialContext();
parser = ctx.getNameParser("");
RefAddr refAddr = new StringRefAddr("nns", "JSMCachePolicy");
String factoryName = DefaultCacheObjectFactory.class.getName();
Reference ref = new Reference("javax.naming.Context", refAddr, factoryName, null);
ctx.rebind(DEFAULT_CACHE_POLICY_PATH, ref);
log.debug("cachePolicyCtxPath="+cacheJndiName);
// Bind the default SecurityProxyFactory instance under java:/SecurityProxyFactory
SecurityProxyFactory proxyFactory = (SecurityProxyFactory) securityProxyFactoryClass.newInstance();
ctx.bind("java:/SecurityProxyFactory", proxyFactory);
log.debug("SecurityProxyFactory="+proxyFactory);
//Handler custom callbackhandler
if(callbackHandlerClass != JBossCallbackHandler.class)
{
AccessController.doPrivileged(new PrivilegedAction<Object>()
{
public Object run()
{
System.setProperty(JNDIBasedSecurityManagement.CBH, callbackHandlerClassName);
return null;
}
});
CallbackHandler callbackHandler = null;
callbackHandler = (CallbackHandler) callbackHandlerClass.newInstance();
if (callbackHandler != null)
securityManagement.setCallBackHandler(callbackHandler);
}
// Set AuthenticationManager class
securityManagement.setAuthenticationMgrClass(securityMgrClassName);
// Register the Principal property editor
PropertyEditorManager.registerEditor(Principal.class, PrincipalEditor.class);
PropertyEditorManager.registerEditor(SecurityDomain.class, SecurityDomainEditor.class);
log.debug("Registered PrincipalEditor, SecurityDomainEditor");
log.debug("ServerMode="+this.serverMode);
log.debug("SecurityMgrClass="+JaasSecurityManagerService.securityMgrClass);
log.debug("CallbackHandlerClass="+JaasSecurityManagerService.callbackHandlerClass);
}
protected void stopService() throws Exception
{
InitialContext ic = new InitialContext();
try
{
ic.unbind(SECURITY_MGR_PATH);
}
catch(CommunicationException e)
{
// Do nothing, the naming services is already stopped
}
finally
{
ic.close();
}
}
/** Register a SecurityDomain implmentation. This is synchronized to ensure
* that the binding of the security domain and cache population is atomic.
* @param securityDomain the name of the security domain
* @param instance the SecurityDomain instance to bind
*/
public synchronized void registerSecurityDomain(String securityDomain, SecurityDomain instance)
{
log.debug("Added "+securityDomain+", "+instance+" to map");
CachePolicy authCache = lookupCachePolicy(securityDomain);
SecurityDomainContext sdc = new SecurityDomainContext(instance, authCache);
securityDomainCtxMap.put(securityDomain, sdc);
// See if the security mgr supports an externalized cache policy
setSecurityDomainCache(instance, authCache);
}
/** Access the CachePolicy for the securityDomain.
* @param securityDomain the name of the security domain
* @return The CachePolicy if found, null otherwise.
*/
private static CachePolicy getCachePolicy(String securityDomain)
{
if( securityDomain.startsWith(SECURITY_MGR_PATH) )
securityDomain = securityDomain.substring(SECURITY_MGR_PATH.length()+1);
CachePolicy cache = null;
try
{
SecurityDomainContext sdc = lookupSecurityDomain(securityDomain);
if( sdc != null )
cache = sdc.getAuthenticationCache();
}
catch(NamingException e)
{
log.debug("getCachePolicy("+securityDomain+") failure", e);
}
return cache;
}
/** Lookup the authentication CachePolicy object for a security domain. This
method first treats the cacheJndiName as a ObjectFactory location that is
capable of returning CachePolicy instances on a per security domain basis
by appending a '/security-domain-name' string to the cacheJndiName when
looking up the CachePolicy for a domain. If this fails then the cacheJndiName
location is treated as a single CachePolicy for all security domains.
*/
static CachePolicy lookupCachePolicy(String securityDomain)
{
CachePolicy authCache = null;
String domainCachePath = cacheJndiName + '/' + securityDomain;
try
{
InitialContext iniCtx = new InitialContext();
authCache = (CachePolicy) iniCtx.lookup(domainCachePath);
}
catch(Exception e)
{
// Failed, treat the cacheJndiName name as a global CachePolicy binding
try
{
InitialContext iniCtx = new InitialContext();
authCache = (CachePolicy) iniCtx.lookup(cacheJndiName);
}
catch(Exception e2)
{
log.warn("Failed to locate auth CachePolicy at: "+cacheJndiName
+ " for securityDomain="+securityDomain);
}
}
return authCache;
}
/** Use reflection to attempt to set the authentication cache on the
* securityMgr argument.
* @param securityMgr the security manager
* @param cachePolicy the cache policy implementation
*/
private static void setSecurityDomainCache(AuthenticationManager securityMgr,
CachePolicy cachePolicy)
{
try
{
Class[] setCachePolicyTypes = {CachePolicy.class};
Method m = securityMgrClass.getMethod("setCachePolicy", setCachePolicyTypes);
Object[] setCachePolicyArgs = {cachePolicy};
m.invoke(securityMgr, setCachePolicyArgs);
log.debug("setCachePolicy, c="+setCachePolicyArgs[0]);
}
catch(Exception e2)
{
if(log.isTraceEnabled())
log.trace("Optional setCachePolicy failed" + e2.getLocalizedMessage());
}
}
/** Use reflection to attempt to set the DeepCopySubject on the
* securityMgr argument.
* @param securityMgr the security manager
* @param flag deep copy subject option
*/
private static void setDeepCopySubjectOption(AuthenticationManager securityMgr,
boolean flag)
{
Boolean bValue = flag ? Boolean.TRUE : Boolean.FALSE;
try
{
Class[] setDeepCopySubjTypes = {Boolean.class};
Method m = securityMgrClass.getMethod("setDeepCopySubjectOption", setDeepCopySubjTypes);
Object[] setDeepCopySubjectOptionArgs = {bValue};
m.invoke(securityMgr, setDeepCopySubjectOptionArgs);
log.debug("setDeepCopySubjectOption, c="+setDeepCopySubjectOptionArgs[0]);
}
catch(Exception e2)
{ // No setDeepCopySubjectOption support, this is ok
log.debug("setDeepCopySubjectOption failed", e2);
}
}
/** Lookup or create the SecurityDomainContext for securityDomain.
* @param securityDomain
* @return the SecurityDomainContext for securityDomain
* @throws NamingException
*/
private synchronized static SecurityDomainContext lookupSecurityDomain(String securityDomain)
throws NamingException
{
SecurityDomainContext securityDomainCtx = (SecurityDomainContext) securityDomainCtxMap.get(securityDomain);
if( securityDomainCtx == null )
{
securityDomainCtx = (SecurityDomainContext) new InitialContext().lookup(
SecurityConstants.JAAS_CONTEXT_ROOT + "/" + securityDomain + "/domainContext");
securityDomainCtxMap.put(securityDomain, securityDomainCtx);
log.debug("Added "+securityDomain+", "+securityDomainCtx+" to map");
}
return securityDomainCtx;
}
/**
* Get the default unauthenticated principal.
* @return The principal name
*/
public String getDefaultUnauthenticatedPrincipal()
{
return defaultUnauthenticatedPrincipal;
}
/**
* Set the default unauthenticated principal.
* @param principal The principal name
*/
public void setDefaultUnauthenticatedPrincipal(String principal)
{
defaultUnauthenticatedPrincipal = principal;
}
/**
* @see JaasSecurityManagerServiceMBean#getJCAInformation()
*/
public String displayJCAInformation()
{
String[] sarr = new String[]{"Cipher","Signature","KeyFactory",
"SecretKeyFactory","AlgorithmParameters",
"MessageDigest","Mac"};
StringBuilder sb = new StringBuilder();
JCASecurityInfo jsi = new JCASecurityInfo();
sb.append("JCA Providers=").append(jsi.getJCAProviderInfo());
sb.append("JCA Service/Algorithms=");
for(String serviceName:sarr)
{
sb.append(jsi.getJCAAlgorithms(serviceName));
}
return sb.toString();
}
static class DomainEnumeration implements NamingEnumeration
{
Enumeration domains;
Map ctxMap;
DomainEnumeration(Enumeration domains, Map ctxMap)
{
this.domains = domains;
this.ctxMap = ctxMap;
}
public void close()
{
}
public boolean hasMoreElements()
{
return domains.hasMoreElements();
}
public boolean hasMore()
{
return domains.hasMoreElements();
}
public Object next()
{
String name = (String) domains.nextElement();
Object value = ctxMap.get(name);
String className = value.getClass().getName();
NameClassPair pair = new NameClassPair(name, className);
return pair;
}
public Object nextElement()
{
return domains.nextElement();
}
}
/** java:/timedCacheFactory ObjectFactory implementation
*/
public static class DefaultCacheObjectFactory implements InvocationHandler, ObjectFactory
{
/** Object factory implementation. This method returns a Context proxy
that is only able to handle a lookup operation for an atomic name of
a security domain.
*/
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment)
throws Exception
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class[] interfaces = {Context.class};
Context ctx = (Context) Proxy.newProxyInstance(loader, interfaces, this);
return ctx;
}
/** This is the InvocationHandler callback for the Context interface that
was created by out getObjectInstance() method. All this does is create
a new TimedCache instance.
*/
public Object invoke(Object obj, Method method, Object[] args) throws Throwable
{
TimedCachePolicy cachePolicy = new TimedCachePolicy(defaultCacheTimeout,
true, defaultCacheResolution);
cachePolicy.create();
cachePolicy.start();
return cachePolicy;
}
}
static ClassLoader getContextClassLoader()
{
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>()
{
public ClassLoader run()
{
return Thread.currentThread().getContextClassLoader();
}
});
}
}