blob: d53b5ca52cf156836076edcce3acf7b91ac04c09 [file] [log] [blame]
/*
* Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jndi.toolkit.ctx;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.*;
import javax.naming.spi.Resolver;
import javax.naming.spi.ResolveResult;
import javax.naming.spi.NamingManager;
/**
* PartialCompositeContext implements Context operations on
* composite names using implementations of the p_ interfaces
* defined by its subclasses.
*
* The main purpose provided by this class is that it deals with
* partial resolutions and continuations, so that callers of the
* Context operation don't have to.
*
* Types of clients that will be direct subclasses of
* PartialCompositeContext may be service providers that implement
* one of the JNDI protocols, but which do not deal with
* continuations. Usually, service providers will be using
* one of the subclasses of PartialCompositeContext.
*
* @author Rosanna Lee
*/
public abstract class PartialCompositeContext implements Context, Resolver {
protected static final int _PARTIAL = 1;
protected static final int _COMPONENT = 2;
protected static final int _ATOMIC = 3;
protected int _contextType = _PARTIAL;
static final CompositeName _EMPTY_NAME = new CompositeName();
static CompositeName _NNS_NAME;
static {
try {
_NNS_NAME = new CompositeName("/");
} catch (InvalidNameException e) {
// Should never happen
}
}
protected PartialCompositeContext() {
}
// ------ Abstract methods whose implementations come from subclasses
/* Equivalent to method in Resolver interface */
protected abstract ResolveResult p_resolveToClass(Name name,
Class contextType, Continuation cont) throws NamingException;
/* Equivalent to methods in Context interface */
protected abstract Object p_lookup(Name name, Continuation cont)
throws NamingException;
protected abstract Object p_lookupLink(Name name, Continuation cont)
throws NamingException;
protected abstract NamingEnumeration p_list(Name name,
Continuation cont) throws NamingException;
protected abstract NamingEnumeration p_listBindings(Name name,
Continuation cont) throws NamingException;
protected abstract void p_bind(Name name, Object obj, Continuation cont)
throws NamingException;
protected abstract void p_rebind(Name name, Object obj, Continuation cont)
throws NamingException;
protected abstract void p_unbind(Name name, Continuation cont)
throws NamingException;
protected abstract void p_destroySubcontext(Name name, Continuation cont)
throws NamingException;
protected abstract Context p_createSubcontext(Name name, Continuation cont)
throws NamingException;
protected abstract void p_rename(Name oldname, Name newname,
Continuation cont)
throws NamingException;
protected abstract NameParser p_getNameParser(Name name, Continuation cont)
throws NamingException;
// ------ should be overridden by subclass;
// ------ not abstract only for backward compatibility
/**
* A cheap way of getting the environment.
* Default implemenation is NOT cheap because it simply calls
* getEnvironment(), which most implementations clone before returning.
* Subclass should ALWAYS override this with the cheapest possible way.
* The toolkit knows to clone when necessary.
* @return The possibly null environment of the context.
*/
protected Hashtable p_getEnvironment() throws NamingException {
return getEnvironment();
}
// ------ implementations of methods in Resolver and Context
// ------ using corresponding p_ methods provided by subclass
/* implementations for method in Resolver interface using p_ method */
public ResolveResult resolveToClass(String name,
Class<? extends Context> contextType)
throws NamingException
{
return resolveToClass(new CompositeName(name), contextType);
}
public ResolveResult resolveToClass(Name name,
Class<? extends Context> contextType)
throws NamingException
{
PartialCompositeContext ctx = this;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
ResolveResult answer;
Name nm = name;
try {
answer = ctx.p_resolveToClass(nm, contextType, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_resolveToClass(nm, contextType, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
if (!(cctx instanceof Resolver)) {
throw e;
}
answer = ((Resolver)cctx).resolveToClass(e.getRemainingName(),
contextType);
}
return answer;
}
/* implementations for methods in Context interface using p_ methods */
public Object lookup(String name) throws NamingException {
return lookup(new CompositeName(name));
}
public Object lookup(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Object answer;
Name nm = name;
try {
answer = ctx.p_lookup(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_lookup(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.lookup(e.getRemainingName());
}
return answer;
}
public void bind(String name, Object newObj) throws NamingException {
bind(new CompositeName(name), newObj);
}
public void bind(Name name, Object newObj) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
ctx.p_bind(nm, newObj, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
ctx.p_bind(nm, newObj, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
cctx.bind(e.getRemainingName(), newObj);
}
}
public void rebind(String name, Object newObj) throws NamingException {
rebind(new CompositeName(name), newObj);
}
public void rebind(Name name, Object newObj) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
ctx.p_rebind(nm, newObj, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
ctx.p_rebind(nm, newObj, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
cctx.rebind(e.getRemainingName(), newObj);
}
}
public void unbind(String name) throws NamingException {
unbind(new CompositeName(name));
}
public void unbind(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
ctx.p_unbind(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
ctx.p_unbind(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
cctx.unbind(e.getRemainingName());
}
}
public void rename(String oldName, String newName) throws NamingException {
rename(new CompositeName(oldName), new CompositeName(newName));
}
public void rename(Name oldName, Name newName)
throws NamingException
{
PartialCompositeContext ctx = this;
Name nm = oldName;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(oldName, env);
try {
ctx.p_rename(nm, newName, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
ctx.p_rename(nm, newName, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
if (e.getRemainingNewName() != null) {
// %%% e.getRemainingNewName() should never be null
newName = e.getRemainingNewName();
}
cctx.rename(e.getRemainingName(), newName);
}
}
public NamingEnumeration<NameClassPair> list(String name)
throws NamingException
{
return list(new CompositeName(name));
}
public NamingEnumeration<NameClassPair> list(Name name)
throws NamingException
{
PartialCompositeContext ctx = this;
Name nm = name;
NamingEnumeration answer;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
answer = ctx.p_list(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_list(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.list(e.getRemainingName());
}
return answer;
}
public NamingEnumeration<Binding> listBindings(String name)
throws NamingException
{
return listBindings(new CompositeName(name));
}
public NamingEnumeration<Binding> listBindings(Name name)
throws NamingException
{
PartialCompositeContext ctx = this;
Name nm = name;
NamingEnumeration answer;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
answer = ctx.p_listBindings(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_listBindings(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.listBindings(e.getRemainingName());
}
return answer;
}
public void destroySubcontext(String name) throws NamingException {
destroySubcontext(new CompositeName(name));
}
public void destroySubcontext(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
ctx.p_destroySubcontext(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
ctx.p_destroySubcontext(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
cctx.destroySubcontext(e.getRemainingName());
}
}
public Context createSubcontext(String name) throws NamingException {
return createSubcontext(new CompositeName(name));
}
public Context createSubcontext(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
Context answer;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
answer = ctx.p_createSubcontext(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_createSubcontext(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.createSubcontext(e.getRemainingName());
}
return answer;
}
public Object lookupLink(String name) throws NamingException {
return lookupLink(new CompositeName(name));
}
public Object lookupLink(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Object answer;
Name nm = name;
try {
answer = ctx.p_lookupLink(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_lookupLink(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.lookupLink(e.getRemainingName());
}
return answer;
}
public NameParser getNameParser(String name) throws NamingException {
return getNameParser(new CompositeName(name));
}
public NameParser getNameParser(Name name) throws NamingException {
PartialCompositeContext ctx = this;
Name nm = name;
NameParser answer;
Hashtable env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
try {
answer = ctx.p_getNameParser(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCContext(cont);
answer = ctx.p_getNameParser(nm, cont);
}
} catch (CannotProceedException e) {
Context cctx = NamingManager.getContinuationContext(e);
answer = cctx.getNameParser(e.getRemainingName());
}
return answer;
}
public String composeName(String name, String prefix)
throws NamingException {
Name fullName = composeName(new CompositeName(name),
new CompositeName(prefix));
return fullName.toString();
}
/**
* This default implementation simply concatenates the two names.
* There's one twist when the "java.naming.provider.compose.elideEmpty"
* environment setting is set to "true": if each name contains a
* nonempty component, and if 'prefix' ends with an empty component or
* 'name' starts with one, then one empty component is dropped.
* For example:
* <pre>
* elideEmpty=false elideEmpty=true
* {"a"} + {"b"} => {"a", "b"} {"a", "b"}
* {"a"} + {""} => {"a", ""} {"a", ""}
* {"a"} + {"", "b"} => {"a", "", "b"} {"a", "b"}
* {"a", ""} + {"b", ""} => {"a", "", "b", ""} {"a", "b", ""}
* {"a", ""} + {"", "b"} => {"a", "", "", "b"} {"a", "", "b"}
* </pre>
*/
public Name composeName(Name name, Name prefix) throws NamingException {
Name res = (Name)prefix.clone();
if (name == null) {
return res;
}
res.addAll(name);
String elide = (String)
p_getEnvironment().get("java.naming.provider.compose.elideEmpty");
if (elide == null || !elide.equalsIgnoreCase("true")) {
return res;
}
int len = prefix.size();
if (!allEmpty(prefix) && !allEmpty(name)) {
if (res.get(len - 1).equals("")) {
res.remove(len - 1);
} else if (res.get(len).equals("")) {
res.remove(len);
}
}
return res;
}
// ------ internal methods used by PartialCompositeContext
/**
* Tests whether a name contains a nonempty component.
*/
protected static boolean allEmpty(Name name) {
Enumeration<String> enum_ = name.getAll();
while (enum_.hasMoreElements()) {
if (!enum_.nextElement().isEmpty()) {
return false;
}
}
return true;
}
/**
* Retrieves a PartialCompositeContext for the resolved object in
* cont. Throws CannotProceedException if not successful.
*/
protected static PartialCompositeContext getPCContext(Continuation cont)
throws NamingException {
Object obj = cont.getResolvedObj();
PartialCompositeContext pctx = null;
if (obj instanceof PartialCompositeContext) {
// Just cast if octx already is PartialCompositeContext
// %%% ignoring environment for now
return (PartialCompositeContext)obj;
} else {
throw cont.fillInException(new CannotProceedException());
}
}
};