User: starksm Date: 01/04/20 22:59:05 Modified: src/main/org/jboss/naming ExternalContext.java ExternalContextMBean.java Log: Add a CacheContext attribute and wrap the external Context in a proxy that ignores user close invocations on inmemory Context objects. Revision Changes Path 1.5 +97 -16 jboss/src/main/org/jboss/naming/ExternalContext.java Index: ExternalContext.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/naming/ExternalContext.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ExternalContext.java 2001/03/14 19:16:24 1.4 +++ ExternalContext.java 2001/04/21 05:59:05 1.5 @@ -12,6 +12,10 @@ import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.net.URL; import java.util.Hashtable; import java.util.Properties; @@ -43,12 +47,10 @@ @see org.jboss.naming.NonSerializableFactory @author [EMAIL PROTECTED] -@version $Revision: 1.4 $ +@version $Revision: 1.5 $ */ public class ExternalContext extends ServiceMBeanSupport implements ExternalContextMBean { - // Constants ----------------------------------------------------- - // Attributes ---------------------------------------------------- private boolean remoteAccess; private SerializableInitialContext contextInfo = new SerializableInitialContext(); @@ -99,6 +101,14 @@ { this.remoteAccess = remoteAccess; } + public boolean getCacheContext() + { + return contextInfo.getCacheContext(); + } + public void setCacheContext(boolean cacheContext) + { + contextInfo.setCacheContext(cacheContext); + } /** Get the class name of the InitialContext implementation to use. Should be one of: @@ -154,7 +164,8 @@ */ public void stopService() { - unbind(contextInfo.getJndiName()); + if( contextInfo.getCacheContext() ) + unbind(contextInfo.getJndiName()); } // Protected ----------------------------------------------------- @@ -197,28 +208,49 @@ log.debug("parentCtx="+parentCtx); Name atomName = fullName.getSuffix(fullName.size()-1); String atom = atomName.get(0); + boolean cacheContext = contextInfo.getCacheContext(); if( remoteAccess == true ) { // Bind contextInfo as a Referenceable parentCtx.rebind(atom, contextInfo); - /* Cache the context in the NonSerializableFactory to avoid creating + /* Cache the context using NonSerializableFactory to avoid creating more than one context for in VM lookups */ - NonSerializableFactory.rebind(jndiName, ctx); + if( cacheContext == true ) + { + /* If cacheContext is true we need to wrap the Context in a + proxy that allows the user to issue close on the lookup + Context without closing the inmemory Context. + */ + ctx = CachedContext.createProxyContext(ctx); + NonSerializableFactory.rebind(jndiName, ctx); + } } - else + else if( cacheContext == true ) { /* Bind a reference to the extern context using - NonSerializableFactory as the ObjectFactory */ - NonSerializableFactory.rebind(rootCtx, jndiName, ctx); + NonSerializableFactory as the ObjectFactory. The Context must + be wrapped in a proxy that allows the user to issue close on the + lookup Context without closing the inmemory Context. + */ + Context proxyCtx = CachedContext.createProxyContext(ctx); + NonSerializableFactory.rebind(rootCtx, jndiName, proxyCtx); } + else + { + /* Bind the contextInfo so that each lookup results in the creation + of a new Context object. The returned Context must be closed + by the user to prevent resource leaks. + */ + parentCtx.rebind(atom, contextInfo); + } } private void unbind(String jndiName) { try { - Context rootCtx = (Context) new InitialContext(); + Context rootCtx = new InitialContext(); Context ctx = (Context) rootCtx.lookup(jndiName); if( ctx != null ) ctx.close(); @@ -242,6 +274,7 @@ private String jndiName; private Class contextClass = javax.naming.InitialContext.class; private Properties contextProps; + private boolean cacheContext = true; private transient Context initialContext; public SerializableInitialContext() @@ -261,6 +294,14 @@ { this.jndiName = jndiName; } + public boolean getCacheContext() + { + return cacheContext; + } + public void setCacheContext(boolean cacheContext) + { + this.cacheContext = cacheContext; + } public String getInitialContext() { return contextClass.getName(); @@ -302,13 +343,11 @@ Context newContext() throws Exception { + // First check the NonSerializableFactory cache + initialContext = (Context) NonSerializableFactory.lookup(jndiName); + // Create the context from the contextClass and contextProps if( initialContext == null ) - { // First check the NonSerializableFactory cache - initialContext = (Context) NonSerializableFactory.lookup(jndiName); - // Create the context from the contextClass and contextProps - if( initialContext == null ) - initialContext = newContext(contextClass, contextProps); - } + initialContext = newContext(contextClass, contextProps); return initialContext; } @@ -366,4 +405,46 @@ } } + /** A proxy implementation of Context that simply intercepts the + close() method and ignores it since the underlying Context + object is being maintained in memory. + */ + static class CachedContext implements InvocationHandler + { + Context externalCtx; + CachedContext(Context externalCtx) + { + this.externalCtx = externalCtx; + } + + static Context createProxyContext(Context ctx) + { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class[] interfaces = ctx.getClass().getInterfaces(); + InvocationHandler handler = new CachedContext(ctx); + Context proxyCtx = (Context) Proxy.newProxyInstance(loader, interfaces, handler); + return proxyCtx; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + Object value = null; + if( method.getName().equals("close") ) + { + // We just ignore the close method + } + else + { + try + { + value = method.invoke(externalCtx, args); + } + catch(InvocationTargetException e) + { + throw e.getTargetException(); + } + } + return value; + } + } } 1.4 +14 -1 jboss/src/main/org/jboss/naming/ExternalContextMBean.java Index: ExternalContextMBean.java =================================================================== RCS file: /cvsroot/jboss/jboss/src/main/org/jboss/naming/ExternalContextMBean.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ExternalContextMBean.java 2001/03/14 06:40:54 1.3 +++ ExternalContextMBean.java 2001/04/21 05:59:05 1.4 @@ -12,7 +12,7 @@ /** The ExternalContext mbean interface. @author [EMAIL PROTECTED] -@version $Revision: 1.3 $ +@version $Revision: 1.4 $ */ public interface ExternalContextMBean extends org.jboss.util.ServiceMBean { @@ -32,6 +32,19 @@ remotely. */ public void setRemoteAccess(boolean remoteAccess); + + /** Get the cacheContext flag. + */ + public boolean getCacheContext(); + /** set the cacheContext flag. When set to true, the external Context + is only created when the mbean is started and then stored as an in + memory object until the mbean is stopped. If cacheContext if set to + false, the external Context is created on each lookup using the + mbean Properties and InitialContext class. When the uncached Context + is looked up by a client, the client should invoke close() on the + Context to prevent resource leaks. + */ + public void setCacheContext(boolean flag); /** Get the class name of the InitialContext implementation to use. Should be one of: _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] http://lists.sourceforge.net/lists/listinfo/jboss-development