[SJN-77] InitialContext.close() improperly throws exception when using JNDI Memory implementation separately | |
| Status: | Closed |
| Project: | Simple-JNDI |
| Component/s: | |
| Affects Version/s: | 0.11.1 |
| Fix Version/s: | 0.11.3 |
| Type: | Bug | Priority: | Major |
| Reporter: | Ludovic Orban | Assignee: | Henri Yandell |
| Resolution: | Fixed | ||
| Environment: | |||
| Description |
| According to this page http://www.osjava.org/simple-jndi/manual/MemoryContext.html it should be possible to use Simple JNDI as an in-memory context. When I try with this jndi.properties in classpath: java.naming.factory.initial=org.osjava.sj.memory.MemoryContextFactory this code: Context ctx = new InitialContext(); ctx.bind("aaa", "bbb"); ctx.close(); throws this exception: java.lang.ClassCastException at org.osjava.sj.jndi.AbstractContext.close(AbstractContext.java:704) at javax.naming.InitialContext.close(InitialContext.java:478) ... and if you set this property in jndi.properties: org.osjava.sj.jndi.shared=true you get that exception instead: javax.naming.NotContextException at org.osjava.sj.jndi.AbstractContext.destroySubcontext(AbstractContext.java:529) at org.osjava.sj.jndi.AbstractContext.close(AbstractContext.java:697) at javax.naming.InitialContext.close(InitialContext.java:478) |
| Comment by bulenterdemir [ Sun, 17 Feb 2008 06:28:27 -0800 (PST) ] |
| Hi, the problem is in the AbstractContext's close() method. This method iterates through the internal HashTable (called table) in which it holds the JNDI bound objects. And while iterating it casts each object from this table to a Thread and tries to see it the thread's are alive by calling isAlive() on them.
So, obviously, if you've bound an object to the JNDI which is NOT a Thread, then the cast operation fails. Here's the code: while(table.size() > 0 || subContexts.size() > 0) { it = table.keySet().iterator(); while(it.hasNext()) { Name name = (Name)it.next(); if(!((Thread)table.get(name)).isAlive()) { table.remove(name); } } I don't understand why the author does this (Thread casting and calling isAlive()), however, this is the cause of your problem. And mine, too... :) Here's a JUnit 4 test to reproduce the problem: package org.falez.falez.jndi.test; import javax.naming.InitialContext; import javax.naming.NamingException; import org.junit.Before; import org.junit.Test; public class TestMemoryContext { InitialContext ic; @Before public void setup() throws NamingException { System.setProperty("java.naming.factory.initial", "org.osjava.sj.memory.MemoryContextFactory"); ic = new InitialContext(); } @Test public void testPut() throws NamingException { String name = "falez:/hoba"; String value = "hoba1"; ic.bind(name, value); String result = (String) ic.lookup(name); ic.close(); } } |
| Comment by bulenterdemir [ Sun, 17 Feb 2008 11:43:51 -0800 (PST) ] |
| Another problem with the MemoryContext is that, the close() method on the AbstractContext, literally closes everything. :)
This means, it releases all the resources related to the particular context: unbind objects, frees up the internal HashTable, etc. This essentially destroys the Jndi registry. However, the close() call should deallocate the resources the JNDI client uses to connect to the JNDI contect. For example, for a remote JNDI connection, the socket should be closed. In other words, when close() is called, the registry should continue to live. If you execute the code below: Context ctx = new InitialContext(); ic.bind("falez:/hoba", "hoba"); ic.close(); the object bound is lost forever. If you create another InitialContext() and try to lookup for the object just bound, you won't find it there. Normally, the resources used to connect to the registry should be freed. Not the JNDI registry itself. Another implication is, if you use Spring's JndiTemplate to access the JNDI registry, you won't be able to use it all because JndiTemplate automatically closes the created InitialContext for every expression it executes. Therefore, after every call, the JNDI registry is destroyed. As a result, AbstractContext's close() method should be empty. Regards, Bulent Erdemir |
| Comment by bayard [ Sat, 22 Mar 2008 13:21:56 -0700 (PDT) ] |
| svn ci -m "Applying Bulent Erdemir's unit test and protecting from the ClassCastException as per Sending simple-jndi/src/java/org/osjava/sj/jndi/AbstractContext.java Adding simple-jndi/src/test/org/osjava/sj/Sjn77Test.java Transmitting file data .. Committed revision 2657. |
| Comment by bayard [ Sat, 22 Mar 2008 13:22:23 -0700 (PDT) ] |
| Still need to deal with the question of what should be in the close() method. |
| Comment by bayard [ Sat, 22 Mar 2008 13:25:56 -0700 (PDT) ] |
| Doesn't fix the NotContextException. |
| Comment by bayard [ Sat, 22 Mar 2008 13:49:01 -0700 (PDT) ] |
| Latter problem is because StaticHashTable is used twice; which makes it the same table.
svn ci -m "Making it so there can be more than one StaticHashtable. This fixes the NotContextException reported in Sending simple-jndi/src/java/org/osjava/sj/jndi/AbstractContext.java Sending simple-jndi/src/java/org/osjava/sj/jndi/StaticHashtable.java Sending simple-jndi/src/test/org/osjava/sj/Sjn77Test.java Transmitting file data ... Committed revision 2658. |
| Comment by bayard [ Sun, 6 Apr 2008 00:31:01 -0700 (PDT) ] |
| As for what should be in the close() method - that's the reason why the Static option exists. In that instance the registry exists beyond the mere object that was created.
So I believe this issue can be closed. |