/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.jndi;
import static org.junit.Assert.*;
import java.util.Hashtable;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.ContextNotEmptyException;
import javax.naming.InitialContext;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NoPermissionException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.test.junit.categories.UnitTest;
/**
* Tests all basic methods of ContextImpl.
*/
@Category(UnitTest.class)
public class ContextJUnitTest {
private Context initialContext;
private Context gemfireContext;
private Context envContext;
private Context dataSourceContext;
@Before
public void setUp() throws Exception {
Hashtable table = new Hashtable();
table.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.geode.internal.jndi.InitialContextFactoryImpl");
initialContext = new InitialContext(table);
initialContext.bind("java:gf/env/datasource/oracle", "a");
gemfireContext = (Context) initialContext.lookup("java:gf");
envContext = (Context) gemfireContext.lookup("env");
dataSourceContext = (Context) envContext.lookup("datasource");
}
@After
public void tearDown() throws Exception {
clearContext(initialContext);
dataSourceContext = null;
envContext = null;
gemfireContext = null;
initialContext = null;
}
/**
* Removes all entries from the specified context, including subcontexts.
*
* @param context context to clear
*/
private void clearContext(Context context) throws NamingException {
for (NamingEnumeration e = context.listBindings(""); e.hasMoreElements();) {
Binding binding = (Binding) e.nextElement();
if (binding.getObject() instanceof Context) {
clearContext((Context) binding.getObject());
}
context.unbind(binding.getName());
}
}
/**
* Tests inability to create duplicate subcontexts.
*/
@Test
public void testSubcontextCreationOfDuplicates() throws NamingException {
// Try to create duplicate subcontext
try {
initialContext.createSubcontext("java:gf");
fail();
} catch (NameAlreadyBoundException expected) {
}
// Try to create duplicate subcontext using multi-component name
try {
gemfireContext.createSubcontext("env/datasource");
fail();
} catch (NameAlreadyBoundException expected) {
}
}
/**
* Tests inability to destroy non empty subcontexts.
*/
@Test
public void testSubcontextNonEmptyDestruction() throws Exception {
// Bind some object in ejb subcontext
dataSourceContext.bind("Test", "Object");
// Attempt to destroy any subcontext
try {
initialContext.destroySubcontext("java:gf");
fail();
} catch (ContextNotEmptyException expected) {
}
try {
initialContext.destroySubcontext("java:gf/env/datasource");
fail();
} catch (ContextNotEmptyException expected) {
}
try {
envContext.destroySubcontext("datasource");
fail();
} catch (ContextNotEmptyException expected) {
}
}
/**
* Tests ability to destroy empty subcontexts.
*/
@Test
public void testSubcontextDestruction() throws Exception {
// Create three new subcontexts
dataSourceContext.createSubcontext("sub1");
dataSourceContext.createSubcontext("sub2");
envContext.createSubcontext("sub3");
// Destroy
initialContext.destroySubcontext("java:gf/env/datasource/sub1");
dataSourceContext.destroySubcontext("sub2");
envContext.destroySubcontext("sub3");
// Perform lookup
try {
dataSourceContext.lookup("sub1");
fail();
} catch (NameNotFoundException expected) {
}
try {
envContext.lookup("datasource/sub2");
fail();
} catch (NameNotFoundException expected) {
}
try {
initialContext.lookup("java:gf/sub3");
fail();
} catch (NameNotFoundException expected) {
}
}
/**
* Tests inability to invoke methods on destroyed subcontexts.
*/
@Test
public void testSubcontextInvokingMethodsOnDestroyedContext() throws Exception {
// Create subcontext and destroy it.
Context sub = dataSourceContext.createSubcontext("sub4");
initialContext.destroySubcontext("java:gf/env/datasource/sub4");
try {
sub.bind("name", "object");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.unbind("name");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.createSubcontext("sub5");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.destroySubcontext("sub6");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.list("");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.lookup("name");
fail();
} catch (NoPermissionException expected) {
}
try {
sub.composeName("name", "prefix");
fail();
} catch (NoPermissionException expected) {
}
try {
NameParserImpl parser = new NameParserImpl();
sub.composeName(parser.parse("a"), parser.parse("b"));
fail();
} catch (NoPermissionException expected) {
}
}
/**
* Tests ability to bind name to object.
*/
@Test
public void testBindLookup() throws Exception {
Object obj1 = new String("Object1");
Object obj2 = new String("Object2");
Object obj3 = new String("Object3");
dataSourceContext.bind("sub21", null);
dataSourceContext.bind("sub22", obj1);
initialContext.bind("java:gf/env/sub23", null);
initialContext.bind("java:gf/env/sub24", obj2);
// Bind to subcontexts that do not exist
initialContext.bind("java:gf/env/datasource/sub25/sub26", obj3);
// Try to lookup
assertNull(dataSourceContext.lookup("sub21"));
assertSame(dataSourceContext.lookup("sub22"), obj1);
assertNull(gemfireContext.lookup("env/sub23"));
assertSame(initialContext.lookup("java:gf/env/sub24"), obj2);
assertSame(dataSourceContext.lookup("sub25/sub26"), obj3);
}
/**
* Tests ability to unbind names.
*/
@Test
public void testUnbind() throws Exception {
envContext.bind("sub31", null);
gemfireContext.bind("env/ejb/sub32", new String("UnbindObject"));
// Unbind
initialContext.unbind("java:gf/env/sub31");
dataSourceContext.unbind("sub32");
try {
envContext.lookup("sub31");
fail();
} catch (NameNotFoundException expected) {
}
try {
initialContext.lookup("java:gf/env/sub32");
fail();
} catch (NameNotFoundException expected) {
}
// Unbind non-existing name
dataSourceContext.unbind("doesNotExist");
// Unbind non-existing name, when subcontext does not exists
try {
gemfireContext.unbind("env/x/y");
fail();
} catch (NameNotFoundException expected) {
}
}
/**
* Tests ability to list bindings for a context - specified by name through object reference.
*/
@Test
public void testListBindings() throws Exception {
gemfireContext.bind("env/datasource/sub41", "ListBindings1");
envContext.bind("sub42", "ListBindings2");
dataSourceContext.bind("sub43", null);
// Verify bindings for context specified by reference
verifyListBindings(envContext, "", "ListBindings1", "ListBindings2");
// Verify bindings for context specified by name
verifyListBindings(initialContext, "java:gf/env", "ListBindings1", "ListBindings2");
}
private void verifyListBindings(Context c, String name, Object obj1, Object obj2)
throws NamingException {
boolean datasourceFoundFlg = false;
boolean o2FoundFlg = false;
boolean datasourceO1FoundFlg = false;
boolean datasourceNullFoundFlg = false;
// List bindings for the specified context
for (NamingEnumeration en = c.listBindings(name); en.hasMore();) {
Binding b = (Binding) en.next();
if (b.getName().equals("datasource")) {
assertEquals(b.getObject(), dataSourceContext);
datasourceFoundFlg = true;
Context nextCon = (Context) b.getObject();
for (NamingEnumeration en1 = nextCon.listBindings(""); en1.hasMore();) {
Binding b1 = (Binding) en1.next();
if (b1.getName().equals("sub41")) {
assertEquals(b1.getObject(), obj1);
datasourceO1FoundFlg = true;
} else if (b1.getName().equals("sub43")) {
// check for null object
assertNull(b1.getObject());
datasourceNullFoundFlg = true;
}
}
} else if (b.getName().equals("sub42")) {
assertEquals(b.getObject(), obj2);
o2FoundFlg = true;
}
}
if (!(datasourceFoundFlg && o2FoundFlg && datasourceO1FoundFlg && datasourceNullFoundFlg)) {
fail();
}
}
@Test
public void testCompositeName() throws Exception {
ContextImpl c = new ContextImpl();
Object o = new Object();
c.rebind("/a/b/c/", o);
assertEquals(c.lookup("a/b/c"), o);
assertEquals(c.lookup("///a/b/c///"), o);
}
@Test
public void testLookup() throws Exception {
ContextImpl ctx = new ContextImpl();
Object obj = new Object();
ctx.rebind("a/b/c/d", obj);
assertEquals(obj, ctx.lookup("a/b/c/d"));
ctx.bind("a", obj);
assertEquals(obj, ctx.lookup("a"));
}
/**
* Tests "getCompositeName" method
*/
@Test
public void testGetCompositeName() throws Exception {
ContextImpl ctx = new ContextImpl();
ctx.rebind("a/b/c/d", new Object());
ContextImpl subCtx;
subCtx = (ContextImpl) ctx.lookup("a");
assertEquals("a", subCtx.getCompoundStringName());
subCtx = (ContextImpl) ctx.lookup("a/b/c");
assertEquals("a/b/c", subCtx.getCompoundStringName());
}
/**
* Tests substitution of '.' with '/' when parsing string names.
*/
@Test
public void testTwoSeparatorNames() throws Exception {
ContextImpl ctx = new ContextImpl();
Object obj = new Object();
ctx.bind("a/b.c.d/e", obj);
assertEquals(ctx.lookup("a/b/c/d/e"), obj);
assertEquals(ctx.lookup("a.b/c.d.e"), obj);
assertTrue(ctx.lookup("a.b.c.d") instanceof Context);
}
}