feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,301 @@
/*
* Copyright (c) 1999, 2011, 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.corba;
// Needed for RMI/IIOP
import java.rmi.Remote;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Enumeration;
import org.omg.CORBA.ORB;
import javax.naming.*;
import com.sun.jndi.cosnaming.CNCtx;
/**
* Contains utilities for performing CORBA-related tasks:
* 1. Get the org.omg.CORBA.Object for a java.rmi.Remote object.
* 2. Create an ORB to use for a given host/port, and environment properties.
*
* @author Simon Nash
* @author Bryan Atsatt
*/
public class CorbaUtils {
/**
* Returns the CORBA object reference associated with a Remote
* object by using the javax.rmi.CORBA package.
*<p>
* Use reflection to avoid hard dependencies on javax.rmi.CORBA package.
* This method effective does the following:
*<blockquote><pre>
* java.lang.Object stub;
* try {
* stub = PortableRemoteObject.toStub(remoteObj);
* } catch (Exception e) {
* throw new ConfigurationException("Object not exported or not found");
* }
* if (!(stub instanceof javax.rmi.CORBA.Stub)) {
* return null; // JRMP impl or JRMP stub
* }
* try {
* ((javax.rmi.CORBA.Stub)stub).connect(orb); // try to connect IIOP stub
* } catch (RemoteException e) {
* // ignore 'already connected' error
* }
* return (javax.rmi.CORBA.Stub)stub;
*
* @param remoteObj The non-null remote object for
* @param orb The non-null ORB to connect the remote object to
* @return The CORBA Object for remoteObj; null if <tt>remoteObj</tt>
* is a JRMP implementation or JRMP stub.
* @exception ClassNotFoundException The RMI-IIOP package is not available
* @exception ConfigurationException The CORBA Object cannot be obtained
* because of configuration problems.
*/
public static org.omg.CORBA.Object remoteToCorba(Remote remoteObj, ORB orb)
throws ClassNotFoundException, ConfigurationException {
synchronized (CorbaUtils.class) {
if (toStubMethod == null) {
initMethodHandles();
}
}
// First, get remoteObj's stub
// javax.rmi.CORBA.Stub stub = PortableRemoteObject.toStub(remoteObj);
java.lang.Object stub;
try {
stub = toStubMethod.invoke(null, new java.lang.Object[]{remoteObj});
} catch (InvocationTargetException e) {
Throwable realException = e.getTargetException();
// realException.printStackTrace();
ConfigurationException ce = new ConfigurationException(
"Problem with PortableRemoteObject.toStub(); object not exported or stub not found");
ce.setRootCause(realException);
throw ce;
} catch (IllegalAccessException e) {
ConfigurationException ce = new ConfigurationException(
"Cannot invoke javax.rmi.PortableRemoteObject.toStub(java.rmi.Remote)");
ce.setRootCause(e);
throw ce;
}
// Next, make sure that the stub is javax.rmi.CORBA.Stub
if (!corbaStubClass.isInstance(stub)) {
return null; // JRMP implementation or JRMP stub
}
// Next, make sure that the stub is connected
// Invoke stub.connect(orb)
try {
connectMethod.invoke(stub, new java.lang.Object[]{orb});
} catch (InvocationTargetException e) {
Throwable realException = e.getTargetException();
// realException.printStackTrace();
if (!(realException instanceof java.rmi.RemoteException)) {
ConfigurationException ce = new ConfigurationException(
"Problem invoking javax.rmi.CORBA.Stub.connect()");
ce.setRootCause(realException);
throw ce;
}
// ignore RemoteException because stub might have already
// been connected
} catch (IllegalAccessException e) {
ConfigurationException ce = new ConfigurationException(
"Cannot invoke javax.rmi.CORBA.Stub.connect()");
ce.setRootCause(e);
throw ce;
}
// Finally, return stub
return (org.omg.CORBA.Object)stub;
}
/**
* Get ORB using given server and port number, and properties from environment.
*
* @param server Possibly null server; if null means use default;
* For applet, it is the applet host; for app, it is localhost.
* @param port Port number, -1 means default port
* @param env Possibly null environment. Contains environment properties.
* Could contain ORB itself; or applet used for initializing ORB.
* Use all String properties from env for initializing ORB
* @return A non-null ORB.
*/
public static ORB getOrb(String server, int port, Hashtable<?,?> env) {
// See if we can get info from environment
Properties orbProp;
// Extract any org.omg.CORBA properties from environment
if (env != null) {
if (env instanceof Properties) {
// Already a Properties, just clone
orbProp = (Properties) env.clone();
} else {
// Get all String properties
Enumeration<?> envProp;
orbProp = new Properties();
for (envProp = env.keys(); envProp.hasMoreElements();) {
String key = (String)envProp.nextElement();
Object val = env.get(key);
if (val instanceof String) {
orbProp.put(key, val);
}
}
}
} else {
orbProp = new Properties();
}
if (server != null) {
orbProp.put("org.omg.CORBA.ORBInitialHost", server);
}
if (port >= 0) {
orbProp.put("org.omg.CORBA.ORBInitialPort", ""+port);
}
// Get Applet from environment
if (env != null) {
Object applet = env.get(Context.APPLET);
if (applet != null) {
// Create ORBs for an applet
return initAppletORB(applet, orbProp);
}
}
// Create ORBs using orbProp for a standalone application
return ORB.init(new String[0], orbProp);
}
/**
* Check whether object factory code base is trusted.
* Classes may only be loaded from an arbitrary URL code base when
* the system property com.sun.jndi.rmi.object.trustURLCodebase
* has been set to "true".
*/
public static boolean isObjectFactoryTrusted(Object obj)
throws NamingException {
// Extract Reference, if possible
Reference ref = null;
if (obj instanceof Reference) {
ref = (Reference) obj;
} else if (obj instanceof Referenceable) {
ref = ((Referenceable)(obj)).getReference();
}
if (ref != null && ref.getFactoryClassLocation() != null &&
!CNCtx.trustURLCodebase) {
throw new ConfigurationException(
"The object factory is untrusted. Set the system property" +
" 'com.sun.jndi.cosnaming.object.trustURLCodebase' to 'true'.");
}
return true;
}
/**
* This method returns a new ORB instance for the given applet
* without creating a static dependency on java.applet.
*/
private static ORB initAppletORB(Object applet, Properties orbProp) {
try {
Class<?> appletClass = Class.forName("java.applet.Applet", true, null);
if (!appletClass.isInstance(applet)) {
throw new ClassCastException(applet.getClass().getName());
}
// invoke the static method ORB.init(applet, orbProp);
Method method = ORB.class.getMethod("init", appletClass, Properties.class);
return (ORB) method.invoke(null, applet, orbProp);
} catch (ClassNotFoundException e) {
// java.applet.Applet doesn't exist and the applet parameter is
// non-null; so throw CCE
throw new ClassCastException(applet.getClass().getName());
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new AssertionError(e);
} catch (IllegalAccessException iae) {
throw new AssertionError(iae);
}
}
// Fields used for reflection of RMI-IIOP
private static Method toStubMethod = null;
private static Method connectMethod = null;
private static Class<?> corbaStubClass = null;
/**
* Initializes reflection method handles for RMI-IIOP.
* @exception ClassNotFoundException javax.rmi.CORBA.* not available
*/
private static void initMethodHandles() throws ClassNotFoundException {
// Get javax.rmi.CORBA.Stub class
corbaStubClass = Class.forName("javax.rmi.CORBA.Stub");
// Get javax.rmi.CORBA.Stub.connect(org.omg.CORBA.ORB) method
try {
connectMethod = corbaStubClass.getMethod("connect",
new Class<?>[] {org.omg.CORBA.ORB.class});
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"No method definition for javax.rmi.CORBA.Stub.connect(org.omg.CORBA.ORB)");
}
// Get javax.rmi.PortableRemoteObject class
Class<?> proClass = Class.forName("javax.rmi.PortableRemoteObject");
// Get javax.rmi.PortableRemoteObject.toStub(java.rmi.Remote) method
try {
toStubMethod = proClass.getMethod("toStub",
new Class<?>[] {java.rmi.Remote.class});
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"No method definition for javax.rmi.PortableRemoteObject.toStub(java.rmi.Remote)");
}
}
}

View File

@@ -0,0 +1,692 @@
/*
* Copyright (c) 1999, 2011, 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 javax.naming.*;
/**
* Clients: deal only with names for its own naming service
* and deals with single contexts that can be built up into
* hierarchical naming systems.
* Direct subclasses of AtomicContext must provide implementations for
* the abstract a_ Context methods, and c_parseComponent().
*
* If the subclass implements the notion of implicit nns,
* it must override the a_*_nns Context methods as well.
*
* @author Rosanna Lee
*
*/
public abstract class AtomicContext extends ComponentContext {
private static int debug = 0;
protected AtomicContext () {
_contextType = _ATOMIC;
}
// ------ Abstract methods whose implementation are provided by subclasses
/* Equivalent to Context methods */
protected abstract Object a_lookup(String name, Continuation cont)
throws NamingException;
protected abstract Object a_lookupLink(String name, Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<NameClassPair> a_list(
Continuation cont) throws NamingException;
protected abstract NamingEnumeration<Binding> a_listBindings(
Continuation cont) throws NamingException;
protected abstract void a_bind(String name, Object obj, Continuation cont)
throws NamingException;
protected abstract void a_rebind(String name, Object obj, Continuation cont)
throws NamingException;
protected abstract void a_unbind(String name, Continuation cont)
throws NamingException;
protected abstract void a_destroySubcontext(String name, Continuation cont)
throws NamingException;
protected abstract Context a_createSubcontext(String name,
Continuation cont) throws NamingException;
protected abstract void a_rename(String oldname, Name newname,
Continuation cont) throws NamingException;
protected abstract NameParser a_getNameParser(Continuation cont)
throws NamingException;
/* Parsing */
/**
* Parse 'inputName' into two parts:
* head: the first component in this name
* tail: the rest of the unused name.
*
* Subclasses should provide an implementation for this method
* which parses inputName using its own name syntax.
*/
protected abstract StringHeadTail c_parseComponent(String inputName,
Continuation cont) throws NamingException;
// ------ Methods that need to be overridden by subclass
/* Resolution method for supporting federation */
/**
* Resolves the nns for 'name' when the named context is acting
* as an intermediate context.
*
* For a system that supports junctions, this would be equilvalent to
* a_lookup(name, cont);
* because for junctions, an intermediate slash simply signifies
* a syntactic separator.
*
* For a system that supports implicit nns, this would be equivalent to
* a_lookup_nns(name, cont);
* because for implicit nns, a slash always signifies the implicit nns,
* regardless of whether it is intermediate or trailing.
*
* By default this method supports junctions, and also allows for an
* implicit nns to be dynamically determined through the use of the
* "nns" reference (see a_processJunction_nns()).
* Contexts that implement implicit nns directly should provide an
* appropriate override.
*/
protected Object a_resolveIntermediate_nns(String name, Continuation cont)
throws NamingException {
try {
final Object obj = a_lookup(name, cont);
// Do not append "" to Continuation 'cont' even if set
// because the intention is to ignore the nns
//
if (obj != null && getClass().isInstance(obj)) {
// If "obj" is in the same type as this object, it must
// not be a junction. Continue the lookup with "/".
cont.setContinueNNS(obj, name, this);
return null;
} else if (obj != null && !(obj instanceof Context)) {
// obj is not even a context, so try to find its nns
// dynamically by constructing a Reference containing obj.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return obj;
}
private static final long serialVersionUID =
-3399518522645918499L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Resolved name has trailing slash to indicate nns
CompositeName resName = new CompositeName();
resName.add(name);
resName.add(""); // add trailing slash
// Set continuation leave it to
// PartialCompositeContext.getPCContext() to throw CPE.
// Do not use setContinueNNS() because we've already
// consumed "/" (i.e., moved it to resName).
cont.setContinue(ref, resName, this);
return null;
} else {
return obj;
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
/* Equivalent of Context Methods for supporting nns */
// The following methods are called when the DirContext methods
// are invoked with a name that has a trailing slash.
// For naming systems that support implicit nns,
// the trailing slash signifies the implicit nns.
// For such naming systems, override these a_*_nns methods.
//
// For naming systems that support junctions (explicit nns),
// the trailing slash is meaningless because a junction does not
// have an implicit nns. The default implementation here
// throws a NameNotFoundException for such names.
// If a context wants to accept a trailing slash as having
// the same meaning as the same name without a trailing slash,
// then it should override these a_*_nns methods.
protected Object a_lookup_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected Object a_lookupLink_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<NameClassPair> a_list_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected NamingEnumeration<Binding> a_listBindings_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected void a_bind_nns(String name, Object obj, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_rebind_nns(String name, Object obj, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_unbind_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected Context a_createSubcontext_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected void a_destroySubcontext_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_rename_nns(String oldname, Name newname, Continuation cont)
throws NamingException {
a_processJunction_nns(oldname, cont);
}
protected NameParser a_getNameParser_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected boolean isEmpty(String name) {
return name == null || name.equals("");
}
// ------ implementations of c_ and c_*_nns methods using
// ------ the corresponding a_ and a_*_nns methods
/* Equivalent to methods in Context interface */
protected Object c_lookup(Name name, Continuation cont)
throws NamingException {
Object ret = null;
if (resolve_to_penultimate_context(name, cont)) {
ret = a_lookup(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
}
protected Object c_lookupLink(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont)) {
return a_lookupLink(name.toString(), cont);
}
return null;
}
protected NamingEnumeration<NameClassPair> c_list(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont)) {
return a_list(cont);
}
return null;
}
protected NamingEnumeration<Binding> c_listBindings(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont)) {
return a_listBindings(cont);
}
return null;
}
protected void c_bind(Name name, Object obj, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_bind(name.toString(), obj, cont);
}
protected void c_rebind(Name name, Object obj, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_rebind(name.toString(), obj, cont);
}
protected void c_unbind(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_unbind(name.toString(), cont);
}
protected void c_destroySubcontext(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_destroySubcontext(name.toString(), cont);
}
protected Context c_createSubcontext(Name name,
Continuation cont) throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_createSubcontext(name.toString(), cont);
else
return null;
}
protected void c_rename(Name oldname, Name newname,
Continuation cont) throws NamingException {
if (resolve_to_penultimate_context(oldname, cont))
a_rename(oldname.toString(), newname, cont);
}
protected NameParser c_getNameParser(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont))
return a_getNameParser(cont);
return null;
}
/* The following are overridden only for AtomicContexts.
* AtomicContext is used by PartialCompositeDirContext and ComponentDirContext
* in the inheritance tree to make use of methods in
* PartialCompositeContext and ComponentContext. We only want to use the
* atomic forms when we're actually an atomic context.
*/
/* From ComponentContext */
protected Object c_resolveIntermediate_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
Object ret = null;
if (resolve_to_penultimate_context_nns(name, cont)) {
ret = a_resolveIntermediate_nns(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
} else {
// use ComponentContext
return super.c_resolveIntermediate_nns(name, cont);
}
}
/* Equivalent to methods in Context interface for nns */
protected Object c_lookup_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
Object ret = null;
if (resolve_to_penultimate_context_nns(name, cont)) {
ret = a_lookup_nns(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
} else {
return super.c_lookup_nns(name, cont);
}
}
protected Object c_lookupLink_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
// %%% check logic
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_lookupLink_nns(name, cont);
}
}
protected NamingEnumeration<NameClassPair> c_list_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_list_nns(name, cont);
}
}
protected NamingEnumeration<Binding> c_listBindings_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_listBindings_nns(name, cont);
}
}
protected void c_bind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_bind_nns(name.toString(), obj, cont);
} else {
// use ComponentContext
super.c_bind_nns(name, obj, cont);
}
}
protected void c_rebind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_rebind_nns(name.toString(), obj, cont);
} else {
// use ComponentContext
super.c_rebind_nns(name, obj, cont);
}
}
protected void c_unbind_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_unbind_nns(name.toString(), cont);
} else {
// use ComponentContext
super.c_unbind_nns(name, cont);
}
}
protected Context c_createSubcontext_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
return a_createSubcontext_nns(name.toString(), cont);
else
return null;
} else {
// use ComponentContext
return super.c_createSubcontext_nns(name, cont);
}
}
protected void c_destroySubcontext_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_destroySubcontext_nns(name.toString(), cont);
} else {
// use ComponentContext
super.c_destroySubcontext_nns(name, cont);
}
}
protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(oldname, cont))
a_rename_nns(oldname.toString(), newname, cont);
} else {
// use ComponentContext
super.c_rename_nns(oldname, newname, cont);
}
}
protected NameParser c_getNameParser_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use COmponentContext
return super.c_getNameParser_nns(name, cont);
}
}
// -------------- internal methods used by this class
/* Handles nns for junctions */
/**
* This function is used when implementing a naming system that
* supports junctions. For example, when the a_bind_nns(name, newobj)
* method is invoked, that means the caller is attempting to bind the
* object 'newobj' to the nns of 'name'. For context that supports
* junctions, 'name' names a junction and is pointing to the root
* of another naming system, which in turn might have an nns.
* This means that a_bind_nns() should first resolve 'name' and attempt to
* continue the operation in the context named by 'name'. (i.e. bind
* to the nns of the context named by 'name').
* If name is already empty, then throw NameNotFoundException because
* this context by default does not have any nns.
*/
protected void a_processJunction_nns(String name, Continuation cont)
throws NamingException {
if (name.equals("")) {
NameNotFoundException e = new NameNotFoundException();
cont.setErrorNNS(this, name);
throw cont.fillInException(e);
}
try {
// lookup name to continue operation in nns
Object target = a_lookup(name, cont);
if (cont.isContinue())
cont.appendRemainingComponent(""); // add nns back
else {
cont.setContinueNNS(target, name, this);
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
/**
* This function is used when implementing a naming system that
* supports junctions. For example, when the a_list_nns(newobj)
* method is invoked, that means the caller is attempting to list the
* the nns context of of this context. For a context that supports
* junctions, it by default does not have any nns. Consequently,
* a NameNotFoundException is thrown.
*/
protected void a_processJunction_nns(Continuation cont) throws NamingException {
// Construct a new Reference that contains this context.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return AtomicContext.this;
}
private static final long serialVersionUID = 3449785852664978312L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Set continuation leave it to PartialCompositeContext.getPCContext()
// to throw the exception.
// Do not use setContinueNNS() because we've are
// setting relativeResolvedName to "/".
cont.setContinue(ref, _NNS_NAME, this);
}
/* *********** core resolution routines ******************* */
/** Resolve to context named by 'name'.
* Returns true if at named context (i.e. 'name' is empty name).
* Returns false otherwise, and sets Continuation on parts of 'name'
* not yet resolved.
*/
protected boolean resolve_to_context(Name name, Continuation cont)
throws NamingException {
String target = name.toString();
StringHeadTail ht = c_parseComponent(target, cont);
String tail = ht.getTail();
String head = ht.getHead();
if (debug > 0)
System.out.println("RESOLVE TO CONTEXT(" + target + ") = {" +
head + ", " + tail + "}");
if (head == null) {
// something is wrong; no name at all
InvalidNameException e = new InvalidNameException();
throw cont.fillInException(e);
}
if (!isEmpty(head)) {
// if there is head is a non-empty name
// this means more resolution to be done
try {
Object headCtx = a_lookup(head, cont);
// System.out.println("answer " + headCtx);
if (headCtx != null)
cont.setContinue(headCtx, head, this, (tail == null ? "" : tail));
else if (cont.isContinue())
cont.appendRemainingComponent(tail);
} catch (NamingException e) {
e.appendRemainingComponent(tail);
throw e;
}
} else {
cont.setSuccess(); // clear
return true;
}
return false;
}
/**
* Resolves to penultimate context named by 'name'.
* Returns true if penultimate context has been reached (i.e. name
* only has one atomic component left).
* Returns false otherwise, and sets Continuation to parts of name
* not yet resolved.
*/
protected boolean resolve_to_penultimate_context(Name name, Continuation cont)
throws NamingException {
String target = name.toString();
if (debug > 0)
System.out.println("RESOLVE TO PENULTIMATE" + target);
StringHeadTail ht = c_parseComponent(target, cont);
String tail = ht.getTail();
String head = ht.getHead();
if (head == null) {
// something is wrong; no name at all
InvalidNameException e = new InvalidNameException();
throw cont.fillInException(e);
}
if (!isEmpty(tail)) {
// more components; hence not at penultimate context yet
try {
Object headCtx = a_lookup(head, cont);
if (headCtx != null)
cont.setContinue(headCtx, head, this, tail);
else if (cont.isContinue())
cont.appendRemainingComponent(tail);
} catch (NamingException e) {
e.appendRemainingComponent(tail);
throw e;
}
} else {
// already at penultimate context
cont.setSuccess(); // clear
return true;
}
return false;
}
/**
* This function is similar to resolve_to_penultimate_context()
* except it should only be called by the nns() functions.
* This function fixes any exception or continuations so that
* it will have the proper nns name.
*/
protected boolean resolve_to_penultimate_context_nns(Name name,
Continuation cont)
throws NamingException {
try {
if (debug > 0)
System.out.println("RESOLVE TO PENULTIMATE NNS" + name.toString());
boolean answer = resolve_to_penultimate_context(name, cont);
// resolve_to_penultimate_context() only calls a_lookup().
// Any continuation it sets is lacking the nns, so
// we need to add it back
if (cont.isContinue())
cont.appendRemainingComponent("");
return answer;
} catch (NamingException e) {
// resolve_to_penultimate_context() only calls a_lookup().
// Any exceptions it throws is lacking the nns, so
// we need to add it back.
e.appendRemainingComponent("");
throw e;
}
}
/**
* Resolves to nns associated with 'name' and set Continuation
* to the result.
*/
protected void resolve_to_nns_and_continue(Name name, Continuation cont)
throws NamingException {
if (debug > 0)
System.out.println("RESOLVE TO NNS AND CONTINUE" + name.toString());
if (resolve_to_penultimate_context_nns(name, cont)) {
Object nns = a_lookup_nns(name.toString(), cont);
if (nns != null)
cont.setContinue(nns, name, this);
}
}
}

View File

@@ -0,0 +1,393 @@
/*
* Copyright (c) 1999, 2011, 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 javax.naming.*;
import javax.naming.directory.*;
/**
* Direct subclasses of AtomicDirContext must provide implementations for
* the abstract a_ DirContext methods, and override the a_ Context methods
* (which are no longer abstract because they have been overriden by
* PartialCompositeDirContext with dummy implementations).
*
* If the subclass implements the notion of implicit nns,
* it must override the a_*_nns DirContext and Context methods as well.
*
* @author Rosanna Lee
*
*/
public abstract class AtomicDirContext extends ComponentDirContext {
protected AtomicDirContext() {
_contextType = _ATOMIC;
}
// ------ Abstract methods whose implementations come from subclass
protected abstract Attributes a_getAttributes(String name, String[] attrIds,
Continuation cont)
throws NamingException;
protected abstract void a_modifyAttributes(String name, int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void a_modifyAttributes(String name,
ModificationItem[] mods,
Continuation cont)
throws NamingException;
protected abstract void a_bind(String name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void a_rebind(String name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract DirContext a_createSubcontext(String name,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> a_search(
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> a_search(
String name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> a_search(
String name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract DirContext a_getSchema(Continuation cont)
throws NamingException;
protected abstract DirContext a_getSchemaClassDefinition(Continuation cont)
throws NamingException;
// ------ Methods that need to be overridden by subclass
// default implementations of a_*_nns methods
// The following methods are called when the DirContext methods
// are invoked with a name that has a trailing slash.
// For naming systems that support implicit nns,
// the trailing slash signifies the implicit nns.
// For such naming systems, override these a_*_nns methods.
//
// For naming systems that support junctions (explicit nns),
// the trailing slash is meaningless because a junction does not
// have an implicit nns. The default implementation here
// throws a NameNotFoundException for such names.
// If a context wants to accept a trailing slash as having
// the same meaning as the same name without a trailing slash,
// then it should override these a_*_nns methods.
protected Attributes a_getAttributes_nns(String name,
String[] attrIds,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected void a_modifyAttributes_nns(String name, int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_modifyAttributes_nns(String name,
ModificationItem[] mods,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_bind_nns(String name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_rebind_nns(String name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected DirContext a_createSubcontext_nns(String name,
Attributes attrs,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> a_search_nns(
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected NamingEnumeration<SearchResult> a_search_nns(String name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> a_search_nns(String name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected DirContext a_getSchema_nns(Continuation cont) throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected DirContext a_getSchemaDefinition_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
// ------- implementations of c_ DirContext methods using corresponding
// ------- a_ and a_*_nns methods
protected Attributes c_getAttributes(Name name, String[] attrIds,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_getAttributes(name.toString(), attrIds, cont);
return null;
}
protected void c_modifyAttributes(Name name, int mod_op,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_modifyAttributes(name.toString(), mod_op, attrs, cont);
}
protected void c_modifyAttributes(Name name, ModificationItem[] mods,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_modifyAttributes(name.toString(), mods, cont);
}
protected void c_bind(Name name, Object obj,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_bind(name.toString(), obj, attrs, cont);
}
protected void c_rebind(Name name, Object obj,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_rebind(name.toString(), obj, attrs, cont);
}
protected DirContext c_createSubcontext(Name name,
Attributes attrs,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_createSubcontext(name.toString(),
attrs, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search(Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException {
if (resolve_to_context(name, cont))
return a_search(matchingAttributes, attributesToReturn, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search(Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_search(name.toString(), filter, cons, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_search(name.toString(), filterExpr, filterArgs, cons, cont);
return null;
}
protected DirContext c_getSchema(Name name, Continuation cont)
throws NamingException {
if (resolve_to_context(name, cont))
return a_getSchema(cont);
return null;
}
protected DirContext c_getSchemaClassDefinition(Name name, Continuation cont)
throws NamingException {
if (resolve_to_context(name, cont))
return a_getSchemaClassDefinition(cont);
return null;
}
/* equivalent to methods in DirContext interface for nns */
protected Attributes c_getAttributes_nns(Name name, String[] attrIds,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
return a_getAttributes_nns(name.toString(), attrIds, cont);
return null;
}
protected void c_modifyAttributes_nns(Name name, int mod_op,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
a_modifyAttributes_nns(name.toString(), mod_op, attrs, cont);
}
protected void c_modifyAttributes_nns(Name name, ModificationItem[] mods,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
a_modifyAttributes_nns(name.toString(), mods, cont);
}
protected void c_bind_nns(Name name, Object obj,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
a_bind_nns(name.toString(), obj, attrs, cont);
}
protected void c_rebind_nns(Name name, Object obj,
Attributes attrs, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
a_rebind_nns(name.toString(), obj, attrs, cont);
}
protected DirContext c_createSubcontext_nns(Name name,
Attributes attrs,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
return a_createSubcontext_nns(name.toString(), attrs, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(
Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException {
resolve_to_nns_and_continue(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
return a_search_nns(name.toString(), filter, cons, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context_nns(name, cont))
return a_search_nns(name.toString(), filterExpr, filterArgs,
cons, cont);
return null;
}
protected DirContext c_getSchema_nns(Name name, Continuation cont)
throws NamingException {
resolve_to_nns_and_continue(name, cont);
return null;
}
protected DirContext c_getSchemaClassDefinition_nns(Name name, Continuation cont)
throws NamingException {
resolve_to_nns_and_continue(name, cont);
return null;
}
}

View File

@@ -0,0 +1,805 @@
/*
* Copyright (c) 1999, 2011, 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 javax.naming.*;
import javax.naming.spi.ResolveResult;
/**
* Provides implementation of p_* operations using
* c_* operations provided by subclasses.
*
* Clients: deal only with names for its own naming service. Must
* provide implementations for c_* methods, and for p_parseComponent()
* and the c_*_nns methods if the defaults are not appropriate.
*
* @author Rosanna Lee
* @author Scott Seligman
*/
public abstract class ComponentContext extends PartialCompositeContext {
private static int debug = 0;
protected ComponentContext() {
_contextType = _COMPONENT;
}
// ------ Abstract methods whose implementation are provided by subclass
/* Equivalent methods in Context interface */
protected abstract Object c_lookup(Name name, Continuation cont)
throws NamingException;
protected abstract Object c_lookupLink(Name name, Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<NameClassPair> c_list(Name name,
Continuation cont) throws NamingException;
protected abstract NamingEnumeration<Binding> c_listBindings(Name name,
Continuation cont) throws NamingException;
protected abstract void c_bind(Name name, Object obj, Continuation cont)
throws NamingException;
protected abstract void c_rebind(Name name, Object obj, Continuation cont)
throws NamingException;
protected abstract void c_unbind(Name name, Continuation cont)
throws NamingException;
protected abstract void c_destroySubcontext(Name name, Continuation cont)
throws NamingException;
protected abstract Context c_createSubcontext(Name name,
Continuation cont) throws NamingException;
protected abstract void c_rename(Name oldname, Name newname,
Continuation cont) throws NamingException;
protected abstract NameParser c_getNameParser(Name name, Continuation cont)
throws NamingException;
// ------ Methods that may need to be overridden by subclass
/* Parsing method */
/**
* Determines which of the first components of 'name' belong
* to this naming system.
* If no components belong to this naming system, return
* the empty name (new CompositeName()) as the head,
* and the entire name as the tail.
*
* The default implementation supports strong separation.
* If the name is empty or if the first component is empty,
* head is the empty name and tail is the entire name.
* (This means that this context does not have any name to work with).
* Otherwise, it returns the first component as head, and the rest of
* the components as tail.
*
* Subclass should override this method according its own policies.
*
* For example, a weakly separated system with dynamic boundary
* determination would simply return as head 'name'.
* A weakly separated with static boundary
* determination would select the components in the front of 'name'
* that conform to some syntax rules. (e.g. in X.500 syntax, perhaps
* select front components that have a equal sign).
* If none conforms, return an empty name.
*/
protected HeadTail p_parseComponent(Name name, Continuation cont)
throws NamingException {
int separator;
// if no name to parse, or if we're already at boundary
if (name.isEmpty() || name.get(0).equals("")) {
separator = 0;
} else {
separator = 1;
}
Name head, tail;
if (name instanceof CompositeName) {
head = name.getPrefix(separator);
tail = name.getSuffix(separator);
} else {
// treat like compound name
head = new CompositeName().add(name.toString());
tail = null;
}
if (debug > 2) {
System.err.println("ORIG: " + name);
System.err.println("PREFIX: " + name);
System.err.println("SUFFIX: " + null);
}
return new HeadTail(head, tail);
}
/* Resolution method for supporting federation */
/**
* Resolves the nns for 'name' when the named context is acting
* as an intermediate context.
*
* For a system that supports only junctions, this would be
* equilvalent to
* c_lookup(name, cont);
* because for junctions, an intermediate slash simply signifies
* a syntactic separator.
*
* For a system that supports only implicit nns, this would be
* equivalent to
* c_lookup_nns(name, cont);
* because for implicit nns, a slash always signifies the implicit nns,
* regardless of whether it is intermediate or trailing.
*
* By default this method supports junctions, and also allows for an
* implicit nns to be dynamically determined through the use of the
* "nns" reference (see c_processJunction_nns()).
* Contexts that implement implicit nns directly should provide an
* appropriate override.
*
* A junction, by definition, is a binding of a name in one
* namespace to an object in another. The default implementation
* of this method detects the crossover into another namespace
* using the following heuristic: there is a junction when "name"
* resolves to a context that is not an instance of
* this.getClass(). Contexts supporting junctions for which this
* heuristic is inappropriate should override this method.
*/
protected Object c_resolveIntermediate_nns(Name name, Continuation cont)
throws NamingException {
try {
final Object obj = c_lookup(name, cont);
// Do not append "" to Continuation 'cont' even if set
// because the intention is to ignore the nns
if (obj != null && getClass().isInstance(obj)) {
// If "obj" is in the same type as this object, it must
// not be a junction. Continue the lookup with "/".
cont.setContinueNNS(obj, name, this);
return null;
} else if (obj != null && !(obj instanceof Context)) {
// obj is not even a context, so try to find its nns
// dynamically by constructing a Reference containing obj.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return obj;
}
private static final long serialVersionUID =
-8831204798861786362L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Resolved name has trailing slash to indicate nns
CompositeName resName = (CompositeName)name.clone();
resName.add(""); // add trailing slash
// Set continuation leave it to
// PartialCompositeContext.getPCContext() to throw CPE.
// Do not use setContinueNNS() because we've already
// consumed "/" (i.e., moved it to resName).
cont.setContinue(ref, resName, this);
return null;
} else {
// Consume "/" and continue
return obj;
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
/* Equivalent of Context Methods for supporting nns */
// The following methods are called when the Context methods
// are invoked with a name that has a trailing slash.
// For naming systems that support implicit nns,
// the trailing slash signifies the implicit nns.
// For such naming systems, override these c_*_nns methods.
//
// For naming systems that do not support implicit nns, the
// default implementations here throw an exception. See
// c_processJunction_nns() for details.
protected Object c_lookup_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected Object c_lookupLink_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<NameClassPair> c_list_nns(Name name,
Continuation cont) throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<Binding> c_listBindings_nns(Name name,
Continuation cont) throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected void c_bind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_rebind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_unbind_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected Context c_createSubcontext_nns(Name name,
Continuation cont) throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected void c_destroySubcontext_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
throws NamingException {
c_processJunction_nns(oldname, cont);
}
protected NameParser c_getNameParser_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
// ------ internal method used by ComponentContext
/**
* Locates the nns using the default policy. This policy fully
* handles junctions, but otherwise throws an exception when an
* attempt is made to resolve an implicit nns.
*
* The default policy is as follows: If there is a junction in
* the namespace, then resolve to the junction and continue the
* operation there (thus deferring to that context to find its own
* nns). Otherwise, resolve as far as possible and then throw
* CannotProceedException with the resolved object being a reference:
* the address type is "nns", and the address contents is this
* context.
*
* For example, when c_bind_nns(name, obj, ...) is invoked, the
* caller is attempting to bind the object "obj" to the nns of
* "name". If "name" is a junction, it names an object in another
* naming system that (presumably) has an nns. c_bind_nns() will
* first resolve "name" to a context and then attempt to continue
* the bind operation there, (thus binding to the nns of the
* context named by "name"). If "name" is empty then throw an
* exception, since this context does not by default support an
* implicit nns.
*
* To implement a context that does support an implicit nns, it is
* necessary to override this default policy. This is done by
* overriding the c_*_nns() methods (which each call this method
* by default).
*/
protected void c_processJunction_nns(Name name, Continuation cont)
throws NamingException
{
if (name.isEmpty()) {
// Construct a new Reference that contains this context.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return ComponentContext.this;
}
private static final long serialVersionUID =
-1389472957988053402L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Set continuation leave it to PartialCompositeContext.getPCContext()
// to throw the exception.
// Do not use setContinueNNS() because we've are
// setting relativeResolvedName to "/".
cont.setContinue(ref, _NNS_NAME, this);
return;
}
try {
// lookup name to continue operation in nns
Object target = c_lookup(name, cont);
if (cont.isContinue())
cont.appendRemainingComponent("");
else {
cont.setContinueNNS(target, name, this);
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
protected static final byte USE_CONTINUATION = 1;
protected static final byte TERMINAL_COMPONENT = 2;
protected static final byte TERMINAL_NNS_COMPONENT = 3;
/**
* Determine whether 'name' is a terminal component in
* this naming system.
* If so, return status indicating so, so that caller
* can perform context operation on this name.
*
* If not, then the first component(s) of 'name' names
* an intermediate context. In that case, resolve these components
* and set Continuation to be the object named.
*
* see test cases at bottom of file.
*/
protected HeadTail p_resolveIntermediate(Name name, Continuation cont)
throws NamingException {
int ret = USE_CONTINUATION;
cont.setSuccess(); // initialize
HeadTail p = p_parseComponent(name, cont);
Name tail = p.getTail();
Name head = p.getHead();
if (tail == null || tail.isEmpty()) {
//System.out.println("terminal : " + head);
ret = TERMINAL_COMPONENT;
} else if (!tail.get(0).equals("")) {
// tail does not begin with "/"
/*
if (head.isEmpty()) {
// Context could not find name that it can use
// illegal syntax error or name not found
//System.out.println("nnf exception : " + head);
NamingException e = new NameNotFoundException();
cont.setError(this, name);
throw cont.fillInException(e);
} else {
*/
// head is being used as intermediate context,
// resolve head and set Continuation with tail
try {
Object obj = c_resolveIntermediate_nns(head, cont);
//System.out.println("resInter : " + head + "=" + obj);
if (obj != null)
cont.setContinue(obj, head, this, tail);
else if (cont.isContinue()) {
checkAndAdjustRemainingName(cont.getRemainingName());
cont.appendRemainingName(tail);
}
} catch (NamingException e) {
checkAndAdjustRemainingName(e.getRemainingName());
e.appendRemainingName(tail);
throw e;
}
/*
}
*/
} else {
// tail begins with "/"
if (tail.size() == 1) {
ret = TERMINAL_NNS_COMPONENT;
//System.out.println("terminal_nns : " + head);
} else if (head.isEmpty() || isAllEmpty(tail)) {
// resolve nns of head and continue with tail.getSuffix(1)
Name newTail = tail.getSuffix(1);
try {
Object obj = c_lookup_nns(head, cont);
//System.out.println("lookup_nns : " + head + "=" + obj);
if (obj != null)
cont.setContinue(obj, head, this, newTail);
else if (cont.isContinue()) {
cont.appendRemainingName(newTail);
// Name rname = cont.getRemainingName();
//System.out.println("cont.rname" + rname);
}
} catch (NamingException e) {
e.appendRemainingName(newTail);
throw e;
}
} else {
// head is being used as intermediate context
// resolve and set continuation to tail
try {
Object obj = c_resolveIntermediate_nns(head, cont);
//System.out.println("resInter2 : " + head + "=" + obj);
if (obj != null)
cont.setContinue(obj, head, this, tail);
else if (cont.isContinue()) {
checkAndAdjustRemainingName(cont.getRemainingName());
cont.appendRemainingName(tail);
}
} catch (NamingException e) {
checkAndAdjustRemainingName(e.getRemainingName());
e.appendRemainingName(tail);
throw e;
}
}
}
p.setStatus(ret);
return p;
}
// When c_resolveIntermediate_nns() or c_lookup_nns() sets up
// its continuation, to indicate "nns", it appends an empty
// component to the remaining name (e.g. "eng/"). If last
// component of remaining name is empty; delete empty component
// before appending tail so that composition of the names work
// correctly. For example, when merging "eng/" and "c.b.a", we want
// the result to be "eng/c.b.a" because the trailing slash in eng
// is extraneous. When merging "" and "c.b.a", we want the result
// to be "/c.b.a" and so must keep the trailing slash (empty name).
void checkAndAdjustRemainingName(Name rname) throws InvalidNameException {
int count;
if (rname != null && (count=rname.size()) > 1 &&
rname.get(count-1).equals("")) {
rname.remove(count-1);
}
}
// Returns true if n contains only empty components
protected boolean isAllEmpty(Name n) {
int count = n.size();
for (int i =0; i < count; i++ ) {
if (!n.get(i).equals("")) {
return false;
}
}
return true;
}
// ------ implementations of p_ Resolver and Context methods using
// ------ corresponding c_ and c_*_nns methods
/* implementation for Resolver method */
protected ResolveResult p_resolveToClass(Name name,
Class<?> contextType,
Continuation cont)
throws NamingException {
if (contextType.isInstance(this)) {
cont.setSuccess();
return (new ResolveResult(this, name));
}
ResolveResult ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
Object obj = p_lookup(name, cont);
if (!cont.isContinue() && contextType.isInstance(obj)) {
ret = new ResolveResult(obj, _EMPTY_NAME);
}
break;
case TERMINAL_COMPONENT:
cont.setSuccess(); // no contextType found; return null
break;
default:
/* USE_CONTINUATION */
/* pcont already set or exception thrown */
break;
}
return ret;
}
/* implementations of p_ Context methods */
protected Object p_lookup(Name name, Continuation cont) throws NamingException {
Object ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
ret = c_lookup_nns(res.getHead(), cont);
if (ret instanceof LinkRef) {
cont.setContinue(ret, res.getHead(), this);
ret = null;
}
break;
case TERMINAL_COMPONENT:
ret = c_lookup(res.getHead(), cont);
if (ret instanceof LinkRef) {
cont.setContinue(ret, res.getHead(), this);
ret = null;
}
break;
default:
/* USE_CONTINUATION */
/* pcont already set or exception thrown */
break;
}
return ret;
}
protected NamingEnumeration<NameClassPair> p_list(Name name, Continuation cont)
throws NamingException {
NamingEnumeration<NameClassPair> ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
if (debug > 0)
System.out.println("c_list_nns(" + res.getHead() + ")");
ret = c_list_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
if (debug > 0)
System.out.println("c_list(" + res.getHead() + ")");
ret = c_list(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return ret;
}
protected NamingEnumeration<Binding> p_listBindings(Name name, Continuation cont) throws
NamingException {
NamingEnumeration<Binding> ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
ret = c_listBindings_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
ret = c_listBindings(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return ret;
}
protected void p_bind(Name name, Object obj, Continuation cont) throws
NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_bind_nns(res.getHead(), obj, cont);
break;
case TERMINAL_COMPONENT:
c_bind(res.getHead(), obj, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_rebind(Name name, Object obj, Continuation cont) throws
NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_rebind_nns(res.getHead(), obj, cont);
break;
case TERMINAL_COMPONENT:
c_rebind(res.getHead(), obj, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_unbind(Name name, Continuation cont) throws
NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_unbind_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
c_unbind(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_destroySubcontext(Name name, Continuation cont) throws
NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_destroySubcontext_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
c_destroySubcontext(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected Context p_createSubcontext(Name name, Continuation cont) throws
NamingException {
Context ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
ret = c_createSubcontext_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
ret = c_createSubcontext(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return ret;
}
protected void p_rename(Name oldName, Name newName, Continuation cont) throws
NamingException {
HeadTail res = p_resolveIntermediate(oldName, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_rename_nns(res.getHead(), newName, cont);
break;
case TERMINAL_COMPONENT:
c_rename(res.getHead(), newName, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected NameParser p_getNameParser(Name name, Continuation cont) throws
NamingException {
NameParser ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
ret = c_getNameParser_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
ret = c_getNameParser(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return ret;
}
protected Object p_lookupLink(Name name, Continuation cont)
throws NamingException {
Object ret = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
ret = c_lookupLink_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
ret = c_lookupLink(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return ret;
}
}
/*
* How p_resolveIntermediate() should behave for various test cases
a.b/x {a.b, x}
c_resolveIntermediate_nns(a.b)
continue(x)
{x,}
terminal(x)
a.b/ {a.b, ""}
terminal_nns(a.b);
a.b//
{a.b, ("", "")}
c_lookup_nns(a.b)
continue({""})
{,""}
terminal_nns({})
/x {{}, {"", x}}
c_lookup_nns({})
continue(x)
{x,}
terminal(x)
//y {{}, {"", "", y}}
c_lookup_nns({})
continue({"", y})
{{}, {"", y}}
c_lookup_nns({})
continue(y)
{y,}
terminal(y)
a.b//y {a.b, {"", y}}
c_resolveIntermediate_nns(a.b)
continue({"", y})
{{}, {"",y}}
c_lookup_nns({});
continue(y)
{y,}
terminal(y);
*
*/

View File

@@ -0,0 +1,470 @@
/*
* Copyright (c) 1999, 2011, 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 javax.naming.*;
import javax.naming.directory.*;
/* Direct subclasses of ComponentDirContext must provide implementations for
* the abstract c_ DirContext methods, and override the c_ Context methods
* (which are no longer abstract because they have been overriden by
* AtomicContext, the direct superclass of PartialDSCompositeContext).
*
* If the subclass is supports implicit nns, it must override all the
* c_*_nns methods corresponding to those in DirContext and Context.
* See ComponentContext for details.
*
* @author Rosanna Lee
*/
public abstract class ComponentDirContext extends PartialCompositeDirContext {
protected ComponentDirContext () {
_contextType = _COMPONENT;
}
// ------ Abstract methods whose implementations are provided by subclass
/* Equivalent to methods in DirContext */
protected abstract Attributes c_getAttributes(Name name,
String[] attrIds,
Continuation cont)
throws NamingException;
protected abstract void c_modifyAttributes(Name name, int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void c_modifyAttributes(Name name,
ModificationItem[] mods,
Continuation cont)
throws NamingException;
protected abstract void c_bind(Name name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void c_rebind(Name name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract DirContext c_createSubcontext(Name name,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> c_search(
Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> c_search(
Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> c_search(
Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract DirContext c_getSchema(Name name, Continuation cont)
throws NamingException;
protected abstract DirContext c_getSchemaClassDefinition(Name name,
Continuation cont)
throws NamingException;
// ------- default implementations of c_*_nns methods from DirContext
// The following methods are called when the DirContext methods
// are invoked with a name that has a trailing slash.
// For naming systems that support implicit nns,
// the trailing slash signifies the implicit nns.
// For such naming systems, override these c_*_nns methods.
//
// For naming systems that support junctions (explicit nns),
// the trailing slash is meaningless because a junction does not
// have an implicit nns. The default implementation here
// throws a NameNotFoundException for such names.
// If a context wants to accept a trailing slash as having
// the same meaning as the same name without a trailing slash,
// then it should override these c_*_nns methods.
// See ComponentContext for details.
protected Attributes c_getAttributes_nns(Name name,
String[] attrIds,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected void c_modifyAttributes_nns(Name name,
int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_modifyAttributes_nns(Name name,
ModificationItem[] mods,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_bind_nns(Name name,
Object obj,
Attributes attrs,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected void c_rebind_nns(Name name,
Object obj,
Attributes attrs,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
}
protected DirContext c_createSubcontext_nns(Name name,
Attributes attrs,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(
Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(
Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration<SearchResult> c_search_nns(
Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected DirContext c_getSchema_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
protected DirContext c_getSchemaClassDefinition_nns(Name name, Continuation cont)
throws NamingException {
c_processJunction_nns(name, cont);
return null;
}
// ------- implementations of p_ DirContext methods using corresponding
// ------- DirContext c_ and c_*_nns methods
/* Implements for abstract methods declared in PartialCompositeDirContext */
protected Attributes p_getAttributes(Name name,
String[] attrIds,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
Attributes answer = null;
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_getAttributes_nns(res.getHead(), attrIds, cont);
break;
case TERMINAL_COMPONENT:
answer = c_getAttributes(res.getHead(), attrIds, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected void p_modifyAttributes(Name name, int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_modifyAttributes_nns(res.getHead(), mod_op, attrs, cont);
break;
case TERMINAL_COMPONENT:
c_modifyAttributes(res.getHead(), mod_op, attrs, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_modifyAttributes(Name name,
ModificationItem[] mods,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_modifyAttributes_nns(res.getHead(), mods, cont);
break;
case TERMINAL_COMPONENT:
c_modifyAttributes(res.getHead(), mods, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_bind(Name name,
Object obj,
Attributes attrs,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_bind_nns(res.getHead(), obj, attrs, cont);
break;
case TERMINAL_COMPONENT:
c_bind(res.getHead(), obj, attrs, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected void p_rebind(Name name, Object obj,
Attributes attrs, Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
c_rebind_nns(res.getHead(), obj, attrs, cont);
break;
case TERMINAL_COMPONENT:
c_rebind(res.getHead(), obj, attrs, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
}
protected DirContext p_createSubcontext(Name name,
Attributes attrs,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
DirContext answer = null;
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_createSubcontext_nns(res.getHead(), attrs, cont);
break;
case TERMINAL_COMPONENT:
answer = c_createSubcontext(res.getHead(), attrs, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected NamingEnumeration<SearchResult> p_search(
Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
NamingEnumeration<SearchResult> answer = null;
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_search_nns(res.getHead(), matchingAttributes,
attributesToReturn, cont);
break;
case TERMINAL_COMPONENT:
answer = c_search(res.getHead(), matchingAttributes,
attributesToReturn, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected NamingEnumeration<SearchResult> p_search(Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
NamingEnumeration<SearchResult> answer = null;
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_search_nns(res.getHead(), filter, cons, cont);
break;
case TERMINAL_COMPONENT:
answer = c_search(res.getHead(), filter, cons, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected NamingEnumeration<SearchResult> p_search(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException {
HeadTail res = p_resolveIntermediate(name, cont);
NamingEnumeration<SearchResult> answer = null;
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_search_nns(res.getHead(),
filterExpr, filterArgs, cons, cont);
break;
case TERMINAL_COMPONENT:
answer = c_search(res.getHead(), filterExpr, filterArgs, cons, cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected DirContext p_getSchema(Name name, Continuation cont)
throws NamingException {
DirContext answer = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_getSchema_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
answer = c_getSchema(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
protected DirContext p_getSchemaClassDefinition(Name name, Continuation cont)
throws NamingException {
DirContext answer = null;
HeadTail res = p_resolveIntermediate(name, cont);
switch (res.getStatus()) {
case TERMINAL_NNS_COMPONENT:
answer = c_getSchemaClassDefinition_nns(res.getHead(), cont);
break;
case TERMINAL_COMPONENT:
answer = c_getSchemaClassDefinition(res.getHead(), cont);
break;
default:
/* USE_CONTINUATION */
/* cont already set or exception thrown */
break;
}
return answer;
}
}

View File

@@ -0,0 +1,442 @@
/*
* Copyright (c) 1999, 2013, 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 javax.naming.*;
import javax.naming.spi.ResolveResult;
import java.util.Hashtable;
/**
* This class contains information required to continue
* the method (place where it left off, and remaining name to
* continue).
*
* @author Rosanna Lee
*/
public class Continuation extends ResolveResult {
/**
* The name that we started out with. It is initialized by the constructor
* and used to calculate to "resolved name" in NamingException in
* fillInException().
* %%% Note that this approach does not always do the calculation
* correctly with respect to absence or presence of the trailing slash
* for resolved name.
*/
protected Name starter;
/**
* Whether links were encountered.
*/
protected Object followingLink = null;
/**
* The environment used by the caller. Initialized by constructor and
* used when filling out a CannotProceedException.
*/
protected Hashtable<?,?> environment = null;
/**
* Indicates whether the Continuation instance indicates that the operation
* should be continued using the data in the Continuation.
* Typically, this is only false if an error has been encountered or if
* the operation has succeeded.
*/
protected boolean continuing = false;
/**
* The last resolved context. Used to set the "AltNameCtx" in a
* CannotProceedException.
*/
protected Context resolvedContext = null;
/**
* The resolved name relative to resolvedContext. Used to set the
* "AltName" in a CannotProceedException.
*/
protected Name relativeResolvedName = null;
/**
* Constructs a new instance of Continuation.
* Used as dummy for contexts that do not do federation (e.g. for schema ops)
*/
public Continuation() {
}
/**
* Constructs a new instance of Continuation.
* @param top The name of the object that is to be resolved/operated upon.
* This becomes the Continuation's 'starter' and is used to
* calculate the "resolved name" when filling in a NamingException.
* @param environment The environment used by the caller. It is used
* when setting the "environment" of a CannotProceedException.
*/
@SuppressWarnings("unchecked") // For Hashtable clone: environment.clone()
public Continuation(Name top, Hashtable<?,?> environment) {
super();
starter = top;
this.environment = (Hashtable<?,?>)
((environment == null) ? null : environment.clone());
}
/**
* Determines whether this Continuation contains data that should be
* used to continue the operation.
*
* @return true if operation should continue; false if operation has
* completed (successfully or unsuccessfully).
*/
public boolean isContinue() {
return continuing;
}
/**
* Sets this Continuation to indicate successful completion.
* Subsequent calls to isContinue() will return false.
* This method is different from the setError() methods only from
* the standpoint that this method does not set any of the other
* fields such as resolved object or resolved context. This is because
* this method is typically called when the context recognizes that
* the operation has successfully completed and that the continuation
* already contains the appropriately set fields.
* @see setError
* @see setErrorNNS
*/
public void setSuccess() {
continuing = false;
}
/**
* Fills in an exception's fields using data from this Continuation.
* The resolved name is set by subtracting remainingName from starter.
* %%% This might not not always produce the correct answer wrt trailing "/".
* If the exception is a CannotProceedException, its environment,
* altName, and altNameCtx fields are set using this continuation's
* environment, relativeResolvedName, and resolvedContext.
*
* @param e The non-null naming exception to fill.
* @return The non-null naming exception with its fields set using
* data from this Continuation.
*/
public NamingException fillInException(NamingException e) {
e.setRemainingName(remainingName);
e.setResolvedObj(resolvedObj);
if (starter == null || starter.isEmpty())
e.setResolvedName(null);
else if (remainingName == null)
e.setResolvedName(starter);
else
e.setResolvedName(
starter.getPrefix(starter.size() -
remainingName.size()));
if ((e instanceof CannotProceedException)) {
CannotProceedException cpe = (CannotProceedException)e;
Hashtable<?,?> env = (environment == null ?
new Hashtable<>(11) : (Hashtable<?,?>)environment.clone());
cpe.setEnvironment(env);
cpe.setAltNameCtx(resolvedContext);
cpe.setAltName(relativeResolvedName);
}
return e;
}
/**
* Sets this Continuation to indicated that an error has occurred,
* and that the remaining name is rename + "/".
*
* This method is typically called by _nns methods that have been
* given a name to process. It might process part of that name but
* encountered some error. Consequenetly, it would call setErrorNNS()
* with the remaining name. Since the _nns method was expected to
* operate upon the "nns" of the original name, the remaining name
* must include the "nns". That's why this method adds a trailing "/".
*<p>
* After this method is called, isContinuing() returns false.
*
* @param resObj The possibly null object that was resolved to.
* @param remain The non-null remaining name.
*/
public void setErrorNNS(Object resObj, Name remain) {
Name nm = (Name)(remain.clone());
try {
nm.add("");
} catch (InvalidNameException e) {
// ignore; can't happen for composite name
}
setErrorAux(resObj, nm);
}
/**
* Form that accepts a String name instead of a Name name.
* @param resObj The possibly null object that was resolved to.
* @param remain The possibly String remaining name.
*
* @see #setErrorNNS(java.lang.Object, javax.naming.Name)
*/
public void setErrorNNS(Object resObj, String remain) {
CompositeName rname = new CompositeName();
try {
if (remain != null && !remain.equals(""))
rname.add(remain);
rname.add("");
} catch (InvalidNameException e) {
// ignore, can't happen for composite name
}
setErrorAux(resObj, rname);
}
/**
* Sets this Continuation to indicated that an error has occurred
* and supply resolved information.
*
* This method is typically called by methods that have been
* given a name to process. It might process part of that name but
* encountered some error. Consequenetly, it would call setError()
* with the resolved object and the remaining name.
*<p>
* After this method is called, isContinuing() returns false.
*
* @param resObj The possibly null object that was resolved to.
* @param remain The possibly null remaining name.
*/
public void setError(Object resObj, Name remain) {
if (remain != null)
remainingName = (Name)(remain.clone());
else
remainingName = null;
setErrorAux(resObj, remainingName);
}
/**
* Form that accepts a String name instead of a Name name.
* @param resObj The possibly null object that was resolved to.
* @param remain The possibly String remaining name.
*
* @see #setError(java.lang.Object, javax.naming.Name)
*/
public void setError(Object resObj, String remain) {
CompositeName rname = new CompositeName();
if (remain != null && !remain.equals("")) {
try {
rname.add(remain);
} catch (InvalidNameException e) {
// ignore; can't happen for composite name
}
}
setErrorAux(resObj, rname);
}
private void setErrorAux(Object resObj, Name rname) {
remainingName = rname;
resolvedObj = resObj;
continuing = false;
}
private void setContinueAux(Object resObj,
Name relResName, Context currCtx, Name remain) {
if (resObj instanceof LinkRef) {
setContinueLink(resObj, relResName, currCtx, remain);
} else {
remainingName = remain;
resolvedObj = resObj;
relativeResolvedName = relResName;
resolvedContext = currCtx;
continuing = true;
}
}
/**
* Sets this Continuation with the supplied data, and set remaining name
* to be "/".
* This method is typically called by _nns methods that have been
* given a name to process. It might the name (without the nns) and
* continue process of the nns elsewhere.
* Consequently, it would call this form of the setContinueNNS().
* This method supplies "/" as the remaining name.
*<p>
* After this method is called, isContinuing() returns true.
*
* @param resObj The possibly null resolved object.
* @param relResName The non-null resolved name relative to currCtx.
* @param currCtx The non-null context from which relResName is to be resolved.
*/
public void setContinueNNS(Object resObj, Name relResName, Context currCtx) {
CompositeName rname = new CompositeName();
setContinue(resObj, relResName, currCtx, PartialCompositeContext._NNS_NAME);
}
/**
* Overloaded form that accesses String names.
*
* @param resObj The possibly null resolved object.
* @param relResName The non-null resolved name relative to currCtx.
* @param currCtx The non-null context from which relResName is to be resolved.
* @see #setContinueNNS(java.lang.Object, javax.naming.Name, javax.naming.Context)
*/
public void setContinueNNS(Object resObj, String relResName, Context currCtx) {
CompositeName relname = new CompositeName();
try {
relname.add(relResName);
} catch (NamingException e) {}
setContinue(resObj, relname, currCtx, PartialCompositeContext._NNS_NAME);
}
/**
* Sets this Continuation with the supplied data, and set remaining name
* to be the empty name.
* This method is typically called by list-style methods
* in which the target context implementing list() expects an
* empty name. For example when c_list() is given a non-empty name to
* process, it would resolve that name, and then call setContinue()
* with the resolved object so that the target context to be listed
* would be called with the empty name (i.e. list the target context itself).
*<p>
* After this method is called, isContinuing() returns true.
*
* @param resObj The possibly null resolved object.
* @param relResName The non-null resolved name relative to currCtx.
* @param currCtx The non-null context from which relResName is to be resolved.
*/
public void setContinue(Object obj, Name relResName, Context currCtx) {
setContinueAux(obj, relResName, currCtx,
(Name)PartialCompositeContext._EMPTY_NAME.clone());
}
/**
* Sets this Continuation with the supplied data.
* This method is typically called by a method that has been asked
* to operate on a name. The method resolves part of the name
* (relResName) to obj and sets the unprocessed part to rename.
* It calls setContinue() so that the operation can be continued
* using this data.
*<p>
* After this method is called, isContinuing() returns true.
*
* @param resObj The possibly null resolved object.
* @param relResName The non-null resolved name relative to currCtx.
* @param currCtx The non-null context from which relResName is to be resolved.
* @param remain The non-null remaining name.
*/
public void setContinue(Object obj, Name relResName, Context currCtx, Name remain) {
if (remain != null)
this.remainingName = (Name)(remain.clone());
else
this.remainingName = new CompositeName();
setContinueAux(obj, relResName, currCtx, remainingName);
}
/**
* String overload.
*
* @param resObj The possibly null resolved object.
* @param relResName The non-null resolved name relative to currCtx.
* @param currCtx The non-null context from which relResName is to be resolved.
* @param remain The non-null remaining name.
* @see #setContinue(java.lang.Object, java.lang.String, javax.naming.Context, java.lang.String)
*/
public void setContinue(Object obj, String relResName,
Context currCtx, String remain) {
CompositeName relname = new CompositeName();
if (!relResName.equals("")) {
try {
relname.add(relResName);
} catch (NamingException e){}
}
CompositeName rname = new CompositeName();
if (!remain.equals("")) {
try {
rname.add(remain);
} catch (NamingException e) {
}
}
setContinueAux(obj, relname, currCtx, rname);
}
/**
* %%% This method is kept only for backward compatibility. Delete when
* old implementations updated.
*
* Replaced by setContinue(obj, relResName, (Context)currCtx);
*
* @deprecated
*/
@Deprecated
public void setContinue(Object obj, Object currCtx) {
setContinue(obj, null, (Context)currCtx);
}
/**
* Sets this Continuation to process a linkRef.
* %%% Not working yet.
*/
private void setContinueLink(Object linkRef, Name relResName,
Context resolvedCtx, Name rname) {
this.followingLink = linkRef;
this.remainingName = rname;
this.resolvedObj = resolvedCtx;
this.relativeResolvedName = PartialCompositeContext._EMPTY_NAME;
this.resolvedContext = resolvedCtx;
this.continuing = true;
}
public String toString() {
if (remainingName != null)
return starter.toString() + "; remainingName: '" + remainingName + "'";
else
return starter.toString();
}
public String toString(boolean detail) {
if (!detail || this.resolvedObj == null)
return this.toString();
return this.toString() + "; resolvedObj: " + this.resolvedObj +
"; relativeResolvedName: " + relativeResolvedName +
"; resolvedContext: " + resolvedContext;
}
private static final long serialVersionUID = 8162530656132624308L;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 1999, 2004, 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 javax.naming.Name;
/**
* A class for returning the result of p_parseComponent();
*
* @author Rosanna Lee
*/
public class HeadTail {
private int status;
private Name head;
private Name tail;
public HeadTail(Name head, Name tail) {
this(head, tail, 0);
}
public HeadTail(Name head, Name tail, int status) {
this.status = status;
this.head = head;
this.tail = tail;
}
public void setStatus(int status) {
this.status = status;
}
public Name getHead() {
return this.head;
}
public Name getTail() {
return this.tail;
}
public int getStatus() {
return this.status;
}
}

View File

@@ -0,0 +1,523 @@
/*
* Copyright (c) 1999, 2013, 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<NameClassPair> p_list(Name name,
Continuation cont) throws NamingException;
protected abstract NamingEnumeration<Binding> 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 implementation 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<NameClassPair> 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<Binding> 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());
}
}
};

View File

@@ -0,0 +1,576 @@
/*
* Copyright (c) 1999, 2011, 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 javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.DirectoryManager;
/*
* Inherit from AtomicContext so that subclasses of PartialCompositeDirContext
* can get the ns methods defined in subclasses of PartialCompositeContext.
*
* Direct subclasses of DirContext should provide implementations for
* the p_ abstract DirContext methods and override the p_ Context methods
* (not abstract anymore because they are overridden by ComponentContext
* (the superclass of AtomicContext)).
*
* @author Rosanna Lee
*/
public abstract class PartialCompositeDirContext
extends AtomicContext implements DirContext {
protected PartialCompositeDirContext() {
_contextType = _PARTIAL;
}
// ------ Abstract methods whose implementation come from subclasses
/* Equivalent to DirContext methods */
protected abstract Attributes p_getAttributes(Name name, String[] attrIds,
Continuation cont)
throws NamingException;
protected abstract void p_modifyAttributes(Name name, int mod_op,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void p_modifyAttributes(Name name,
ModificationItem[] mods,
Continuation cont)
throws NamingException;
protected abstract void p_bind(Name name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract void p_rebind(Name name, Object obj,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract DirContext p_createSubcontext(Name name,
Attributes attrs,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> p_search(
Name name,
Attributes matchingAttributes,
String[] attributesToReturn,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> p_search(
Name name,
String filter,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract NamingEnumeration<SearchResult> p_search(
Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons,
Continuation cont)
throws NamingException;
protected abstract DirContext p_getSchema(Name name, Continuation cont)
throws NamingException;
protected abstract DirContext p_getSchemaClassDefinition(Name name,
Continuation cont)
throws NamingException;
// ------ implementation for DirContext methods using
// ------ corresponding p_ methods
public Attributes getAttributes(String name)
throws NamingException {
return getAttributes(name, null);
}
public Attributes getAttributes(Name name)
throws NamingException {
return getAttributes(name, null);
}
public Attributes getAttributes(String name, String[] attrIds)
throws NamingException {
return getAttributes(new CompositeName(name), attrIds);
}
public Attributes getAttributes(Name name, String[] attrIds)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Attributes answer;
Name nm = name;
try {
answer = ctx.p_getAttributes(nm, attrIds, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_getAttributes(nm, attrIds, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.getAttributes(e.getRemainingName(), attrIds);
}
return answer;
}
public void modifyAttributes(String name, int mod_op, Attributes attrs)
throws NamingException {
modifyAttributes(new CompositeName(name), mod_op, attrs);
}
public void modifyAttributes(Name name, int mod_op, Attributes attrs)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Name nm = name;
try {
ctx.p_modifyAttributes(nm, mod_op, attrs, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
ctx.p_modifyAttributes(nm, mod_op, attrs, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
cctx.modifyAttributes(e.getRemainingName(), mod_op, attrs);
}
}
public void modifyAttributes(String name, ModificationItem[] mods)
throws NamingException {
modifyAttributes(new CompositeName(name), mods);
}
public void modifyAttributes(Name name, ModificationItem[] mods)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Name nm = name;
try {
ctx.p_modifyAttributes(nm, mods, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
ctx.p_modifyAttributes(nm, mods, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
cctx.modifyAttributes(e.getRemainingName(), mods);
}
}
public void bind(String name, Object obj, Attributes attrs)
throws NamingException {
bind(new CompositeName(name), obj, attrs);
}
public void bind(Name name, Object obj, Attributes attrs)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Name nm = name;
try {
ctx.p_bind(nm, obj, attrs, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
ctx.p_bind(nm, obj, attrs, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
cctx.bind(e.getRemainingName(), obj, attrs);
}
}
public void rebind(String name, Object obj, Attributes attrs)
throws NamingException {
rebind(new CompositeName(name), obj, attrs);
}
public void rebind(Name name, Object obj, Attributes attrs)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
Name nm = name;
try {
ctx.p_rebind(nm, obj, attrs, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
ctx.p_rebind(nm, obj, attrs, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
cctx.rebind(e.getRemainingName(), obj, attrs);
}
}
public DirContext createSubcontext(String name, Attributes attrs)
throws NamingException {
return createSubcontext(new CompositeName(name), attrs);
}
public DirContext createSubcontext(Name name, Attributes attrs)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
DirContext answer;
Name nm = name;
try {
answer = ctx.p_createSubcontext(nm, attrs, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_createSubcontext(nm, attrs, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.createSubcontext(e.getRemainingName(), attrs);
}
return answer;
}
public NamingEnumeration<SearchResult>
search(String name, Attributes matchingAttributes)
throws NamingException
{
return search(name, matchingAttributes, null);
}
public NamingEnumeration<SearchResult>
search(Name name, Attributes matchingAttributes)
throws NamingException
{
return search(name, matchingAttributes, null);
}
public NamingEnumeration<SearchResult>
search(String name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException
{
return search(new CompositeName(name),
matchingAttributes, attributesToReturn);
}
public NamingEnumeration<SearchResult>
search(Name name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException
{
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
NamingEnumeration<SearchResult> answer;
Name nm = name;
try {
answer = ctx.p_search(nm, matchingAttributes,
attributesToReturn, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_search(nm, matchingAttributes,
attributesToReturn, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.search(e.getRemainingName(), matchingAttributes,
attributesToReturn);
}
return answer;
}
public NamingEnumeration<SearchResult>
search(String name,
String filter,
SearchControls cons)
throws NamingException
{
return search(new CompositeName(name), filter, cons);
}
public NamingEnumeration<SearchResult>
search(Name name,
String filter,
SearchControls cons)
throws NamingException
{
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
NamingEnumeration<SearchResult> answer;
Name nm = name;
try {
answer = ctx.p_search(nm, filter, cons, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_search(nm, filter, cons, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.search(e.getRemainingName(), filter, cons);
}
return answer;
}
public NamingEnumeration<SearchResult>
search(String name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException
{
return search(new CompositeName(name), filterExpr, filterArgs, cons);
}
public NamingEnumeration<SearchResult>
search(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException
{
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
NamingEnumeration<SearchResult> answer;
Name nm = name;
try {
answer = ctx.p_search(nm, filterExpr, filterArgs, cons, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_search(nm, filterExpr, filterArgs, cons, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.search(e.getRemainingName(), filterExpr, filterArgs,
cons);
}
return answer;
}
public DirContext getSchema(String name) throws NamingException {
return getSchema(new CompositeName(name));
}
public DirContext getSchema(Name name) throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
DirContext answer;
Name nm = name;
try {
answer = ctx.p_getSchema(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_getSchema(nm, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.getSchema(e.getRemainingName());
}
return answer;
}
public DirContext getSchemaClassDefinition(String name)
throws NamingException {
return getSchemaClassDefinition(new CompositeName(name));
}
public DirContext getSchemaClassDefinition(Name name)
throws NamingException {
PartialCompositeDirContext ctx = this;
Hashtable<?,?> env = p_getEnvironment();
Continuation cont = new Continuation(name, env);
DirContext answer;
Name nm = name;
try {
answer = ctx.p_getSchemaClassDefinition(nm, cont);
while (cont.isContinue()) {
nm = cont.getRemainingName();
ctx = getPCDirContext(cont);
answer = ctx.p_getSchemaClassDefinition(nm, cont);
}
} catch (CannotProceedException e) {
DirContext cctx = DirectoryManager.getContinuationDirContext(e);
answer = cctx.getSchemaClassDefinition(e.getRemainingName());
}
return answer;
}
// ------ internal method used by PartialCompositeDirContext
/**
* Retrieves a PartialCompositeDirContext for the resolved object in
* cont. Throws CannotProceedException if not successful.
*/
protected static PartialCompositeDirContext getPCDirContext(Continuation cont)
throws NamingException {
PartialCompositeContext pctx =
PartialCompositeContext.getPCContext(cont);
if (!(pctx instanceof PartialCompositeDirContext)) {
throw cont.fillInException(
new NotContextException(
"Resolved object is not a DirContext."));
}
return (PartialCompositeDirContext)pctx;
}
//------ Compensation for inheriting from AtomicContext
/*
* Dummy implementations defined here so that direct subclasses
* of PartialCompositeDirContext or ComponentDirContext do not
* have to provide dummy implementations for these.
* Override these for subclasses of AtomicDirContext.
*/
protected StringHeadTail c_parseComponent(String inputName,
Continuation cont) throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected Object a_lookup(String name, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected Object a_lookupLink(String name, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected NamingEnumeration<NameClassPair> a_list(
Continuation cont) throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected NamingEnumeration<Binding> a_listBindings(
Continuation cont) throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected void a_bind(String name, Object obj, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected void a_rebind(String name, Object obj, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected void a_unbind(String name, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected void a_destroySubcontext(String name, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected Context a_createSubcontext(String name, Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected void a_rename(String oldname, Name newname,
Continuation cont) throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
protected NameParser a_getNameParser(Continuation cont)
throws NamingException {
OperationNotSupportedException e = new
OperationNotSupportedException();
throw cont.fillInException(e);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 1999, 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;
/**
* A class for returning the result of c_parseComponent().
*
* @author Rosanna Lee
*/
public class StringHeadTail {
private int status;
private String head;
private String tail;
public StringHeadTail(String head, String tail) {
this(head, tail, 0);
}
public StringHeadTail(String head, String tail, int status) {
this.status = status;
this.head = head;
this.tail = tail;
}
public void setStatus(int status) {
this.status = status;
}
public String getHead() {
return this.head;
}
public String getTail() {
return this.tail;
}
public int getStatus() {
return this.status;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 1999, 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.dir;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* Is implemented by classes that can perform filter checks on
* an attribute set.
*/
public interface AttrFilter {
/**
* Determines whether an attribute passes the filter.
*/
public boolean check(Attributes targetAttrs) throws NamingException;
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 1999, 2011, 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.
*/
/**
* Supports checking an attribute set satisfies a filter
* that is specified as a set of "matching" attributes.
* Checking is done by determining whether the given attribute set
* is a superset of the matching ones.
*
* @author Rosanna Lee
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.*;
public class ContainmentFilter implements AttrFilter {
private Attributes matchingAttrs;
public ContainmentFilter(Attributes match) {
matchingAttrs = match;
}
public boolean check(Attributes attrs) throws NamingException {
return matchingAttrs == null ||
matchingAttrs.size() == 0 ||
contains(attrs, matchingAttrs);
}
// returns true if superset contains subset
public static boolean contains(Attributes superset, Attributes subset)
throws NamingException {
if (subset == null)
return true; // an empty set is always a subset
NamingEnumeration<? extends Attribute> m = subset.getAll();
while (m.hasMore()) {
if (superset == null) {
return false; // contains nothing
}
Attribute target = m.next();
Attribute fromSuper = superset.get(target.getID());
if (fromSuper == null) {
return false;
} else {
// check whether attribute values match
if (target.size() > 0) {
NamingEnumeration<?> vals = target.getAll();
while (vals.hasMore()) {
if (!fromSuper.contains(vals.next())) {
return false;
}
}
}
}
}
return true;
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 1999, 2013, 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.dir;
import javax.naming.*;
import javax.naming.directory.SearchControls;
import java.util.*;
/**
* A class for recursively enumerating the contents of a Context;
*
* @author Jon Ruiz
*/
public class ContextEnumerator implements NamingEnumeration<Binding> {
private static boolean debug = false;
private NamingEnumeration<Binding> children = null;
private Binding currentChild = null;
private boolean currentReturned = false;
private Context root;
private ContextEnumerator currentChildEnum = null;
private boolean currentChildExpanded = false;
private boolean rootProcessed = false;
private int scope = SearchControls.SUBTREE_SCOPE;
private String contextName = "";
public ContextEnumerator(Context context) throws NamingException {
this(context, SearchControls.SUBTREE_SCOPE);
}
public ContextEnumerator(Context context, int scope)
throws NamingException {
// return this object except when searching single-level
this(context, scope, "", scope != SearchControls.ONELEVEL_SCOPE);
}
protected ContextEnumerator(Context context, int scope, String contextName,
boolean returnSelf)
throws NamingException {
if(context == null) {
throw new IllegalArgumentException("null context passed");
}
root = context;
// No need to list children if we're only searching object
if (scope != SearchControls.OBJECT_SCOPE) {
children = getImmediateChildren(context);
}
this.scope = scope;
this.contextName = contextName;
// pretend root is processed, if we're not supposed to return ourself
rootProcessed = !returnSelf;
prepNextChild();
}
// Subclass should override if it wants to avoid calling obj factory
protected NamingEnumeration<Binding> getImmediateChildren(Context ctx)
throws NamingException {
return ctx.listBindings("");
}
// Subclass should override so that instance is of same type as subclass
protected ContextEnumerator newEnumerator(Context ctx, int scope,
String contextName, boolean returnSelf) throws NamingException {
return new ContextEnumerator(ctx, scope, contextName, returnSelf);
}
public boolean hasMore() throws NamingException {
return !rootProcessed ||
(scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants());
}
public boolean hasMoreElements() {
try {
return hasMore();
} catch (NamingException e) {
return false;
}
}
public Binding nextElement() {
try {
return next();
} catch (NamingException e) {
throw new NoSuchElementException(e.toString());
}
}
public Binding next() throws NamingException {
if (!rootProcessed) {
rootProcessed = true;
return new Binding("", root.getClass().getName(),
root, true);
}
if (scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants()) {
return getNextDescendant();
}
throw new NoSuchElementException();
}
public void close() throws NamingException {
root = null;
}
private boolean hasMoreChildren() throws NamingException {
return children != null && children.hasMore();
}
private Binding getNextChild() throws NamingException {
Binding oldBinding = children.next();
Binding newBinding = null;
// if the name is relative, we need to add it to the name of this
// context to keep it relative w.r.t. the root context we are
// enumerating
if(oldBinding.isRelative() && !contextName.equals("")) {
NameParser parser = root.getNameParser("");
Name newName = parser.parse(contextName);
newName.add(oldBinding.getName());
if(debug) {
System.out.println("ContextEnumerator: adding " + newName);
}
newBinding = new Binding(newName.toString(),
oldBinding.getClassName(),
oldBinding.getObject(),
oldBinding.isRelative());
} else {
if(debug) {
System.out.println("ContextEnumerator: using old binding");
}
newBinding = oldBinding;
}
return newBinding;
}
private boolean hasMoreDescendants() throws NamingException {
// if the current child is expanded, see if it has more elements
if (!currentReturned) {
if(debug) {System.out.println("hasMoreDescendants returning " +
(currentChild != null) ); }
return currentChild != null;
} else if (currentChildExpanded && currentChildEnum.hasMore()) {
if(debug) {System.out.println("hasMoreDescendants returning " +
"true");}
return true;
} else {
if(debug) {System.out.println("hasMoreDescendants returning " +
"hasMoreChildren");}
return hasMoreChildren();
}
}
private Binding getNextDescendant() throws NamingException {
if (!currentReturned) {
// returning parent
if(debug) {System.out.println("getNextDescedant: simple case");}
currentReturned = true;
return currentChild;
} else if (currentChildExpanded && currentChildEnum.hasMore()) {
if(debug) {System.out.println("getNextDescedant: expanded case");}
// if the current child is expanded, use it's enumerator
return currentChildEnum.next();
} else {
// Ready to go onto next child
if(debug) {System.out.println("getNextDescedant: next case");}
prepNextChild();
return getNextDescendant();
}
}
private void prepNextChild() throws NamingException {
if(hasMoreChildren()) {
try {
currentChild = getNextChild();
currentReturned = false;
} catch (NamingException e){
if (debug) System.out.println(e);
if (debug) e.printStackTrace();
}
} else {
currentChild = null;
return;
}
if(scope == SearchControls.SUBTREE_SCOPE &&
currentChild.getObject() instanceof Context) {
currentChildEnum = newEnumerator(
(Context)(currentChild.getObject()),
scope, currentChild.getName(),
false);
currentChildExpanded = true;
if(debug) {System.out.println("prepNextChild: expanded");}
} else {
currentChildExpanded = false;
currentChildEnum = null;
if(debug) {System.out.println("prepNextChild: normal");}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 1999, 2011, 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.dir;
import javax.naming.*;
import javax.naming.directory.*;
/**
* A class for searching DirContexts
*
* @author Jon Ruiz
*/
public class DirSearch {
public static NamingEnumeration<SearchResult> search(DirContext ctx,
Attributes matchingAttributes,
String[] attributesToReturn) throws NamingException {
SearchControls cons = new SearchControls(
SearchControls.ONELEVEL_SCOPE,
0, 0, attributesToReturn,
false, false);
return new LazySearchEnumerationImpl(
new ContextEnumerator(ctx, SearchControls.ONELEVEL_SCOPE),
new ContainmentFilter(matchingAttributes),
cons);
}
public static NamingEnumeration<SearchResult> search(DirContext ctx,
String filter, SearchControls cons) throws NamingException {
if (cons == null)
cons = new SearchControls();
return new LazySearchEnumerationImpl(
new ContextEnumerator(ctx, cons.getSearchScope()),
new SearchFilter(filter),
cons);
}
public static NamingEnumeration<SearchResult> search(DirContext ctx,
String filterExpr, Object[] filterArgs, SearchControls cons)
throws NamingException {
String strfilter = SearchFilter.format(filterExpr, filterArgs);
return search(ctx, strfilter, cons);
}
}

View File

@@ -0,0 +1,962 @@
/*
* Copyright (c) 1999, 2011, 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.dir;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.*;
import java.util.*;
/**
* A sample service provider that implements a hierarchical directory in memory.
* Every operation begins by doing a lookup on the name passed to it and then
* calls a corresponding "do<OperationName>" on the result of the lookup. The
* "do<OperationName>" does the work without any further resolution (it assumes
* that it is the target context).
*/
public class HierMemDirCtx implements DirContext {
static private final boolean debug = false;
private static final NameParser defaultParser = new HierarchicalNameParser();
protected Hashtable<String, Object> myEnv;
protected Hashtable<Name, Object> bindings;
protected Attributes attrs;
protected boolean ignoreCase = false;
protected NamingException readOnlyEx = null;
protected NameParser myParser = defaultParser;
private boolean alwaysUseFactory;
public void close() throws NamingException {
myEnv = null;
bindings = null;
attrs = null;
}
public String getNameInNamespace() throws NamingException {
throw new OperationNotSupportedException(
"Cannot determine full name");
}
public HierMemDirCtx() {
this(null, false, false);
}
public HierMemDirCtx(boolean ignoreCase) {
this(null, ignoreCase, false);
}
public HierMemDirCtx(Hashtable<String, Object> environment, boolean ignoreCase) {
this(environment, ignoreCase, false);
}
protected HierMemDirCtx(Hashtable<String, Object> environment,
boolean ignoreCase, boolean useFac) {
myEnv = environment;
this.ignoreCase = ignoreCase;
init();
this.alwaysUseFactory = useFac;
}
private void init() {
attrs = new BasicAttributes(ignoreCase);
bindings = new Hashtable<>(11, 0.75f);
}
public Object lookup(String name) throws NamingException {
return lookup(myParser.parse(name));
}
public Object lookup(Name name) throws NamingException {
return doLookup(name, alwaysUseFactory);
}
public Object doLookup(Name name, boolean useFactory)
throws NamingException {
Object target = null;
name = canonizeName(name);
switch(name.size()) {
case 0:
// name is empty, caller wants this object
target = this;
break;
case 1:
// name is atomic, caller wants one of this object's bindings
target = bindings.get(name);
break;
default:
// name is compound, delegate to child context
HierMemDirCtx ctx = (HierMemDirCtx)bindings.get(name.getPrefix(1));
if(ctx == null) {
target = null;
} else {
target = ctx.doLookup(name.getSuffix(1), false);
}
break;
}
if(target == null) {
throw new NameNotFoundException(name.toString());
}
if (useFactory) {
try {
return DirectoryManager.getObjectInstance(target,
name, this, myEnv,
(target instanceof HierMemDirCtx) ?
((HierMemDirCtx)target).attrs : null);
} catch (NamingException e) {
throw e;
} catch (Exception e) {
NamingException e2 = new NamingException(
"Problem calling getObjectInstance");
e2.setRootCause(e);
throw e2;
}
} else {
return target;
}
}
public void bind(String name, Object obj) throws NamingException {
bind(myParser.parse(name), obj);
}
public void bind(Name name, Object obj) throws NamingException {
doBind(name, obj, null, alwaysUseFactory);
}
public void bind(String name, Object obj, Attributes attrs)
throws NamingException {
bind(myParser.parse(name), obj, attrs);
}
public void bind(Name name, Object obj, Attributes attrs)
throws NamingException {
doBind(name, obj, attrs, alwaysUseFactory);
}
protected void doBind(Name name, Object obj, Attributes attrs,
boolean useFactory) throws NamingException {
if (name.isEmpty()) {
throw new InvalidNameException("Cannot bind empty name");
}
if (useFactory) {
DirStateFactory.Result res = DirectoryManager.getStateToBind(
obj, name, this, myEnv, attrs);
obj = res.getObject();
attrs = res.getAttributes();
}
HierMemDirCtx ctx= (HierMemDirCtx) doLookup(getInternalName(name), false);
ctx.doBindAux(getLeafName(name), obj);
if (attrs != null && attrs.size() > 0) {
modifyAttributes(name, ADD_ATTRIBUTE, attrs);
}
}
protected void doBindAux(Name name, Object obj) throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
if (bindings.get(name) != null) {
throw new NameAlreadyBoundException(name.toString());
}
if(obj instanceof HierMemDirCtx) {
bindings.put(name, obj);
} else {
throw new SchemaViolationException(
"This context only supports binding objects of it's own kind");
}
}
public void rebind(String name, Object obj) throws NamingException {
rebind(myParser.parse(name), obj);
}
public void rebind(Name name, Object obj) throws NamingException {
doRebind(name, obj, null, alwaysUseFactory);
}
public void rebind(String name, Object obj, Attributes attrs)
throws NamingException {
rebind(myParser.parse(name), obj, attrs);
}
public void rebind(Name name, Object obj, Attributes attrs)
throws NamingException {
doRebind(name, obj, attrs, alwaysUseFactory);
}
protected void doRebind(Name name, Object obj, Attributes attrs,
boolean useFactory) throws NamingException {
if (name.isEmpty()) {
throw new InvalidNameException("Cannot rebind empty name");
}
if (useFactory) {
DirStateFactory.Result res = DirectoryManager.getStateToBind(
obj, name, this, myEnv, attrs);
obj = res.getObject();
attrs = res.getAttributes();
}
HierMemDirCtx ctx= (HierMemDirCtx) doLookup(getInternalName(name), false);
ctx.doRebindAux(getLeafName(name), obj);
//
// attrs == null -> use attrs from obj
// attrs != null -> use attrs
//
// %%% Strictly speaking, when attrs is non-null, we should
// take the explicit step of removing obj's attrs.
// We don't do that currently.
if (attrs != null && attrs.size() > 0) {
modifyAttributes(name, ADD_ATTRIBUTE, attrs);
}
}
protected void doRebindAux(Name name, Object obj) throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
if(obj instanceof HierMemDirCtx) {
bindings.put(name, obj);
} else {
throw new SchemaViolationException(
"This context only supports binding objects of it's own kind");
}
}
public void unbind(String name) throws NamingException {
unbind(myParser.parse(name));
}
public void unbind(Name name) throws NamingException {
if (name.isEmpty()) {
throw new InvalidNameException("Cannot unbind empty name");
} else {
HierMemDirCtx ctx=
(HierMemDirCtx) doLookup(getInternalName(name), false);
ctx.doUnbind(getLeafName(name));
}
}
protected void doUnbind(Name name) throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
bindings.remove(name); // attrs will also be removed along with ctx
}
public void rename(String oldname, String newname)
throws NamingException {
rename(myParser.parse(oldname), myParser.parse(newname));
}
public void rename(Name oldname, Name newname)
throws NamingException {
if(newname.isEmpty() || oldname.isEmpty()) {
throw new InvalidNameException("Cannot rename empty name");
}
if (!getInternalName(newname).equals(getInternalName(oldname))) {
throw new InvalidNameException("Cannot rename across contexts");
}
HierMemDirCtx ctx =
(HierMemDirCtx) doLookup(getInternalName(newname), false);
ctx.doRename(getLeafName(oldname), getLeafName(newname));
}
protected void doRename(Name oldname, Name newname) throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
oldname = canonizeName(oldname);
newname = canonizeName(newname);
// Check if new name exists
if (bindings.get(newname) != null) {
throw new NameAlreadyBoundException(newname.toString());
}
// Check if old name is bound
Object oldBinding = bindings.remove(oldname);
if (oldBinding == null) {
throw new NameNotFoundException(oldname.toString());
}
bindings.put(newname, oldBinding);
}
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
return list(myParser.parse(name));
}
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
return ctx.doList();
}
protected NamingEnumeration<NameClassPair> doList () throws NamingException {
return new FlatNames(bindings.keys());
}
public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
return listBindings(myParser.parse(name));
}
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
HierMemDirCtx ctx = (HierMemDirCtx)doLookup(name, false);
return ctx.doListBindings(alwaysUseFactory);
}
protected NamingEnumeration<Binding> doListBindings(boolean useFactory)
throws NamingException {
return new FlatBindings(bindings, myEnv, useFactory);
}
public void destroySubcontext(String name) throws NamingException {
destroySubcontext(myParser.parse(name));
}
public void destroySubcontext(Name name) throws NamingException {
HierMemDirCtx ctx =
(HierMemDirCtx) doLookup(getInternalName(name), false);
ctx.doDestroySubcontext(getLeafName(name));
}
protected void doDestroySubcontext(Name name) throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
name = canonizeName(name);
bindings.remove(name);
}
public Context createSubcontext(String name) throws NamingException {
return createSubcontext(myParser.parse(name));
}
public Context createSubcontext(Name name) throws NamingException {
return createSubcontext(name, null);
}
public DirContext createSubcontext(String name, Attributes attrs)
throws NamingException {
return createSubcontext(myParser.parse(name), attrs);
}
public DirContext createSubcontext(Name name, Attributes attrs)
throws NamingException {
HierMemDirCtx ctx =
(HierMemDirCtx) doLookup(getInternalName(name), false);
return ctx.doCreateSubcontext(getLeafName(name), attrs);
}
protected DirContext doCreateSubcontext(Name name, Attributes attrs)
throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
name = canonizeName(name);
if (bindings.get(name) != null) {
throw new NameAlreadyBoundException(name.toString());
}
HierMemDirCtx newCtx = createNewCtx();
bindings.put(name, newCtx);
if(attrs != null) {
newCtx.modifyAttributes("", ADD_ATTRIBUTE, attrs);
}
return newCtx;
}
public Object lookupLink(String name) throws NamingException {
// This context does not treat links specially
return lookupLink(myParser.parse(name));
}
public Object lookupLink(Name name) throws NamingException {
// Flat namespace; no federation; just call string version
return lookup(name);
}
public NameParser getNameParser(String name) throws NamingException {
return myParser;
}
public NameParser getNameParser(Name name) throws NamingException {
return myParser;
}
public String composeName(String name, String prefix)
throws NamingException {
Name result = composeName(new CompositeName(name),
new CompositeName(prefix));
return result.toString();
}
public Name composeName(Name name, Name prefix)
throws NamingException {
name = canonizeName(name);
prefix = canonizeName(prefix);
Name result = (Name)(prefix.clone());
result.addAll(name);
return result;
}
@SuppressWarnings("unchecked") // clone()
public Object addToEnvironment(String propName, Object propVal)
throws NamingException {
myEnv = (myEnv == null)
? new Hashtable<String, Object>(11, 0.75f)
: (Hashtable<String, Object>)myEnv.clone();
return myEnv.put(propName, propVal);
}
@SuppressWarnings("unchecked") // clone()
public Object removeFromEnvironment(String propName)
throws NamingException {
if (myEnv == null)
return null;
myEnv = (Hashtable<String, Object>)myEnv.clone();
return myEnv.remove(propName);
}
@SuppressWarnings("unchecked") // clone()
public Hashtable<String, Object> getEnvironment() throws NamingException {
if (myEnv == null) {
return new Hashtable<>(5, 0.75f);
} else {
return (Hashtable<String, Object>)myEnv.clone();
}
}
public Attributes getAttributes(String name)
throws NamingException {
return getAttributes(myParser.parse(name));
}
public Attributes getAttributes(Name name)
throws NamingException {
HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
return ctx.doGetAttributes();
}
protected Attributes doGetAttributes() throws NamingException {
return (Attributes)attrs.clone();
}
public Attributes getAttributes(String name, String[] attrIds)
throws NamingException {
return getAttributes(myParser.parse(name), attrIds);
}
public Attributes getAttributes(Name name, String[] attrIds)
throws NamingException {
HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
return ctx.doGetAttributes(attrIds);
}
protected Attributes doGetAttributes(String[] attrIds)
throws NamingException {
if (attrIds == null) {
return doGetAttributes();
}
Attributes attrs = new BasicAttributes(ignoreCase);
Attribute attr = null;
for(int i=0; i<attrIds.length; i++) {
attr = this.attrs.get(attrIds[i]);
if (attr != null) {
attrs.put(attr);
}
}
return attrs;
}
public void modifyAttributes(String name, int mod_op, Attributes attrs)
throws NamingException {
modifyAttributes(myParser.parse(name), mod_op, attrs);
}
public void modifyAttributes(Name name, int mod_op, Attributes attrs)
throws NamingException {
if (attrs == null || attrs.size() == 0) {
throw new IllegalArgumentException(
"Cannot modify without an attribute");
}
// turn it into a modification Enumeration and pass it on
NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll();
ModificationItem[] mods = new ModificationItem[attrs.size()];
for (int i = 0; i < mods.length && attrEnum.hasMoreElements(); i++) {
mods[i] = new ModificationItem(mod_op, attrEnum.next());
}
modifyAttributes(name, mods);
}
public void modifyAttributes(String name, ModificationItem[] mods)
throws NamingException {
modifyAttributes(myParser.parse(name), mods);
}
public void modifyAttributes(Name name, ModificationItem[] mods)
throws NamingException {
HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
ctx.doModifyAttributes(mods);
}
protected void doModifyAttributes(ModificationItem[] mods)
throws NamingException {
if (readOnlyEx != null) {
throw (NamingException) readOnlyEx.fillInStackTrace();
}
applyMods(mods, attrs);
}
protected static Attributes applyMods(ModificationItem[] mods,
Attributes orig) throws NamingException {
ModificationItem mod;
Attribute existingAttr, modAttr;
NamingEnumeration<?> modVals;
for (int i = 0; i < mods.length; i++) {
mod = mods[i];
modAttr = mod.getAttribute();
switch(mod.getModificationOp()) {
case ADD_ATTRIBUTE:
if (debug) {
System.out.println("HierMemDSCtx: adding " +
mod.getAttribute().toString());
}
existingAttr = orig.get(modAttr.getID());
if (existingAttr == null) {
orig.put((Attribute)modAttr.clone());
} else {
// Add new attribute values to existing attribute
modVals = modAttr.getAll();
while (modVals.hasMore()) {
existingAttr.add(modVals.next());
}
}
break;
case REPLACE_ATTRIBUTE:
if (modAttr.size() == 0) {
orig.remove(modAttr.getID());
} else {
orig.put((Attribute)modAttr.clone());
}
break;
case REMOVE_ATTRIBUTE:
existingAttr = orig.get(modAttr.getID());
if (existingAttr != null) {
if (modAttr.size() == 0) {
orig.remove(modAttr.getID());
} else {
// Remove attribute values from existing attribute
modVals = modAttr.getAll();
while (modVals.hasMore()) {
existingAttr.remove(modVals.next());
}
if (existingAttr.size() == 0) {
orig.remove(modAttr.getID());
}
}
}
break;
default:
throw new AttributeModificationException("Unknown mod_op");
}
}
return orig;
}
public NamingEnumeration<SearchResult> search(String name,
Attributes matchingAttributes)
throws NamingException {
return search(name, matchingAttributes, null);
}
public NamingEnumeration<SearchResult> search(Name name,
Attributes matchingAttributes)
throws NamingException {
return search(name, matchingAttributes, null);
}
public NamingEnumeration<SearchResult> search(String name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException {
return search(myParser.parse(name), matchingAttributes,
attributesToReturn);
}
public NamingEnumeration<SearchResult> search(Name name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException {
HierMemDirCtx target = (HierMemDirCtx) doLookup(name, false);
SearchControls cons = new SearchControls();
cons.setReturningAttributes(attributesToReturn);
return new LazySearchEnumerationImpl(
target.doListBindings(false),
new ContainmentFilter(matchingAttributes),
cons, this, myEnv,
false); // alwaysUseFactory ignored because objReturnFlag == false
}
public NamingEnumeration<SearchResult> search(Name name,
String filter,
SearchControls cons)
throws NamingException {
DirContext target = (DirContext) doLookup(name, false);
SearchFilter stringfilter = new SearchFilter(filter);
return new LazySearchEnumerationImpl(
new HierContextEnumerator(target,
(cons != null) ? cons.getSearchScope() :
SearchControls.ONELEVEL_SCOPE),
stringfilter,
cons, this, myEnv, alwaysUseFactory);
}
public NamingEnumeration<SearchResult> search(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException {
String strfilter = SearchFilter.format(filterExpr, filterArgs);
return search(name, strfilter, cons);
}
public NamingEnumeration<SearchResult> search(String name,
String filter,
SearchControls cons)
throws NamingException {
return search(myParser.parse(name), filter, cons);
}
public NamingEnumeration<SearchResult> search(String name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException {
return search(myParser.parse(name), filterExpr, filterArgs, cons);
}
// This function is called whenever a new object needs to be created.
// this is used so that if anyone subclasses us, they can override this
// and return object of their own kind.
protected HierMemDirCtx createNewCtx() throws NamingException {
return new HierMemDirCtx(myEnv, ignoreCase);
}
// If the supplied name is a composite name, return the name that
// is its first component.
protected Name canonizeName(Name name) throws NamingException {
Name canonicalName = name;
if(!(name instanceof HierarchicalName)) {
// If name is not of the correct type, make copy
canonicalName = new HierarchicalName();
int n = name.size();
for(int i = 0; i < n; i++) {
canonicalName.add(i, name.get(i));
}
}
return canonicalName;
}
protected Name getInternalName(Name name) throws NamingException {
return (name.getPrefix(name.size() - 1));
}
protected Name getLeafName(Name name) throws NamingException {
return (name.getSuffix(name.size() - 1));
}
public DirContext getSchema(String name) throws NamingException {
throw new OperationNotSupportedException();
}
public DirContext getSchema(Name name) throws NamingException {
throw new OperationNotSupportedException();
}
public DirContext getSchemaClassDefinition(String name)
throws NamingException {
throw new OperationNotSupportedException();
}
public DirContext getSchemaClassDefinition(Name name)
throws NamingException {
throw new OperationNotSupportedException();
}
// Set context in readonly mode; throw e when update operation attempted.
public void setReadOnly(NamingException e) {
readOnlyEx = e;
}
// Set context to support case-insensitive names
public void setIgnoreCase(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
}
public void setNameParser(NameParser parser) {
myParser = parser;
}
/*
* Common base class for FlatNames and FlatBindings.
*/
private abstract class BaseFlatNames<T> implements NamingEnumeration<T> {
Enumeration<Name> names;
BaseFlatNames (Enumeration<Name> names) {
this.names = names;
}
public final boolean hasMoreElements() {
try {
return hasMore();
} catch (NamingException e) {
return false;
}
}
public final boolean hasMore() throws NamingException {
return names.hasMoreElements();
}
public final T nextElement() {
try {
return next();
} catch (NamingException e) {
throw new NoSuchElementException(e.toString());
}
}
public abstract T next() throws NamingException;
public final void close() {
names = null;
}
}
// Class for enumerating name/class pairs
private final class FlatNames extends BaseFlatNames<NameClassPair> {
FlatNames (Enumeration<Name> names) {
super(names);
}
@Override
public NameClassPair next() throws NamingException {
Name name = names.nextElement();
String className = bindings.get(name).getClass().getName();
return new NameClassPair(name.toString(), className);
}
}
// Class for enumerating bindings
private final class FlatBindings extends BaseFlatNames<Binding> {
private Hashtable<Name, Object> bds;
private Hashtable<String, Object> env;
private boolean useFactory;
FlatBindings(Hashtable<Name, Object> bindings,
Hashtable<String, Object> env,
boolean useFactory) {
super(bindings.keys());
this.env = env;
this.bds = bindings;
this.useFactory = useFactory;
}
@Override
public Binding next() throws NamingException {
Name name = names.nextElement();
HierMemDirCtx obj = (HierMemDirCtx)bds.get(name);
Object answer = obj;
if (useFactory) {
Attributes attrs = obj.getAttributes(""); // only method available
try {
answer = DirectoryManager.getObjectInstance(obj,
name, HierMemDirCtx.this, env, attrs);
} catch (NamingException e) {
throw e;
} catch (Exception e) {
NamingException e2 = new NamingException(
"Problem calling getObjectInstance");
e2.setRootCause(e);
throw e2;
}
}
return new Binding(name.toString(), answer);
}
}
public class HierContextEnumerator extends ContextEnumerator {
public HierContextEnumerator(Context context, int scope)
throws NamingException {
super(context, scope);
}
protected HierContextEnumerator(Context context, int scope,
String contextName, boolean returnSelf) throws NamingException {
super(context, scope, contextName, returnSelf);
}
protected NamingEnumeration<Binding> getImmediateChildren(Context ctx)
throws NamingException {
return ((HierMemDirCtx)ctx).doListBindings(false);
}
protected ContextEnumerator newEnumerator(Context ctx, int scope,
String contextName, boolean returnSelf) throws NamingException {
return new HierContextEnumerator(ctx, scope, contextName,
returnSelf);
}
}
}
// CompundNames's HashCode() method isn't good enough for many string.
// The only prupose of this subclass is to have a more discerning
// hash function. We'll make up for the performance hit by caching
// the hash value.
final class HierarchicalName extends CompoundName {
private int hashValue = -1;
// Creates an empty name
HierarchicalName() {
super(new Enumeration<String>() {
public boolean hasMoreElements() {return false;}
public String nextElement() {throw new NoSuchElementException();}
},
HierarchicalNameParser.mySyntax);
}
HierarchicalName(Enumeration<String> comps, Properties syntax) {
super(comps, syntax);
}
HierarchicalName(String n, Properties syntax) throws InvalidNameException {
super(n, syntax);
}
// just like String.hashCode, only it pays no attention to length
public int hashCode() {
if (hashValue == -1) {
String name = toString().toUpperCase(Locale.ENGLISH);
int len = name.length();
int off = 0;
char val[] = new char[len];
name.getChars(0, len, val, 0);
for (int i = len; i > 0; i--) {
hashValue = (hashValue * 37) + val[off++];
}
}
return hashValue;
}
public Name getPrefix(int posn) {
Enumeration<String> comps = super.getPrefix(posn).getAll();
return (new HierarchicalName(comps, mySyntax));
}
public Name getSuffix(int posn) {
Enumeration<String> comps = super.getSuffix(posn).getAll();
return (new HierarchicalName(comps, mySyntax));
}
public Object clone() {
return (new HierarchicalName(getAll(), mySyntax));
}
private static final long serialVersionUID = -6717336834584573168L;
}
// This is the default name parser (used if setNameParser is not called)
final class HierarchicalNameParser implements NameParser {
static final Properties mySyntax = new Properties();
static {
mySyntax.put("jndi.syntax.direction", "left_to_right");
mySyntax.put("jndi.syntax.separator", "/");
mySyntax.put("jndi.syntax.ignorecase", "true");
mySyntax.put("jndi.syntax.escape", "\\");
mySyntax.put("jndi.syntax.beginquote", "\"");
//mySyntax.put("jndi.syntax.separator.ava", "+");
//mySyntax.put("jndi.syntax.separator.typeval", "=");
mySyntax.put("jndi.syntax.trimblanks", "false");
};
public Name parse(String name) throws NamingException {
return new HierarchicalName(name, mySyntax);
}
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) 1999, 2013, 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.
*/
/**
* Given an enumeration of candidates, check whether each
* item in enumeration satifies the given filter.
* Each item is a Binding and the following is used to get its
* attributes for used by the filter:
*
* ((DirContext)item.getObject()).getAttributes("").
* If item.getObject() is not an DirContext, the item is skipped
*
* The items in the enumeration are obtained one at a time as
* items from the search enumeration are requested.
*
* @author Rosanna Lee
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.DirectoryManager;
import java.util.NoSuchElementException;
import java.util.Hashtable;
final public class LazySearchEnumerationImpl
implements NamingEnumeration<SearchResult> {
private NamingEnumeration<Binding> candidates;
private SearchResult nextMatch = null;
private SearchControls cons;
private AttrFilter filter;
private Context context;
private Hashtable<String, Object> env;
private boolean useFactory = true;
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons) throws NamingException {
this.candidates = candidates;
this.filter = filter;
if(cons == null) {
this.cons = new SearchControls();
} else {
this.cons = cons;
}
}
@SuppressWarnings("unchecked") // For Hashtable clone: env.clone()
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons,
Context ctx, Hashtable<String, Object> env, boolean useFactory)
throws NamingException {
this.candidates = candidates;
this.filter = filter;
this.env = (Hashtable<String, Object>)
((env == null) ? null : env.clone());
this.context = ctx;
this.useFactory = useFactory;
if(cons == null) {
this.cons = new SearchControls();
} else {
this.cons = cons;
}
}
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons,
Context ctx, Hashtable<String, Object> env) throws NamingException {
this(candidates, filter, cons, ctx, env, true);
}
public boolean hasMore() throws NamingException {
// find and do not remove from list
return findNextMatch(false) != null;
}
public boolean hasMoreElements() {
try {
return hasMore();
} catch (NamingException e) {
return false;
}
}
public SearchResult nextElement() {
try {
return findNextMatch(true);
} catch (NamingException e) {
throw new NoSuchElementException(e.toString());
}
}
public SearchResult next() throws NamingException {
// find and remove from list
return (findNextMatch(true));
}
public void close() throws NamingException {
if (candidates != null) {
candidates.close();
}
}
private SearchResult findNextMatch(boolean remove) throws NamingException {
SearchResult answer;
if (nextMatch != null) {
answer = nextMatch;
if (remove) {
nextMatch = null;
}
return answer;
} else {
// need to find next match
Binding next;
Object obj;
Attributes targetAttrs;
while (candidates.hasMore()) {
next = candidates.next();
obj = next.getObject();
if (obj instanceof DirContext) {
targetAttrs = ((DirContext)(obj)).getAttributes("");
if (filter.check(targetAttrs)) {
if (!cons.getReturningObjFlag()) {
obj = null;
} else if (useFactory) {
try {
// Give name only if context non-null,
// otherewise, name will be interpreted relative
// to initial context (not what we want)
Name nm = (context != null ?
new CompositeName(next.getName()) : null);
obj = DirectoryManager.getObjectInstance(obj,
nm, context, env, targetAttrs);
} catch (NamingException e) {
throw e;
} catch (Exception e) {
NamingException e2 = new NamingException(
"problem generating object using object factory");
e2.setRootCause(e);
throw e2;
}
}
answer = new SearchResult(next.getName(),
next.getClassName(), obj,
SearchFilter.selectAttributes(targetAttrs,
cons.getReturningAttributes()),
true);
if (!remove)
nextMatch = answer;
return answer;
}
}
}
return null;
}
}
}

View File

@@ -0,0 +1,677 @@
/*
* Copyright (c) 1999, 2013, 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.dir;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Locale;
/**
* A class for parsing LDAP search filters (defined in RFC 1960, 2254)
*
* @author Jon Ruiz
* @author Rosanna Lee
*/
public class SearchFilter implements AttrFilter {
interface StringFilter extends AttrFilter {
public void parse() throws InvalidSearchFilterException;
}
// %%% "filter" and "pos" are not declared "private" due to bug 4064984.
String filter;
int pos;
private StringFilter rootFilter;
protected static final boolean debug = false;
protected static final char BEGIN_FILTER_TOKEN = '(';
protected static final char END_FILTER_TOKEN = ')';
protected static final char AND_TOKEN = '&';
protected static final char OR_TOKEN = '|';
protected static final char NOT_TOKEN = '!';
protected static final char EQUAL_TOKEN = '=';
protected static final char APPROX_TOKEN = '~';
protected static final char LESS_TOKEN = '<';
protected static final char GREATER_TOKEN = '>';
protected static final char EXTEND_TOKEN = ':';
protected static final char WILDCARD_TOKEN = '*';
public SearchFilter(String filter) throws InvalidSearchFilterException {
this.filter = filter;
pos = 0;
normalizeFilter();
rootFilter = this.createNextFilter();
}
// Returns true if targetAttrs passes the filter
public boolean check(Attributes targetAttrs) throws NamingException {
if (targetAttrs == null)
return false;
return rootFilter.check(targetAttrs);
}
/*
* Utility routines used by member classes
*/
// does some pre-processing on the string to make it look exactly lik
// what the parser expects. This only needs to be called once.
protected void normalizeFilter() {
skipWhiteSpace(); // get rid of any leading whitespaces
// Sometimes, search filters don't have "(" and ")" - add them
if(getCurrentChar() != BEGIN_FILTER_TOKEN) {
filter = BEGIN_FILTER_TOKEN + filter + END_FILTER_TOKEN;
}
// this would be a good place to strip whitespace if desired
if(debug) {System.out.println("SearchFilter: normalized filter:" +
filter);}
}
private void skipWhiteSpace() {
while (Character.isWhitespace(getCurrentChar())) {
consumeChar();
}
}
protected StringFilter createNextFilter()
throws InvalidSearchFilterException {
StringFilter filter;
skipWhiteSpace();
try {
// make sure every filter starts with "("
if(getCurrentChar() != BEGIN_FILTER_TOKEN) {
throw new InvalidSearchFilterException("expected \"" +
BEGIN_FILTER_TOKEN +
"\" at position " +
pos);
}
// skip past the "("
this.consumeChar();
skipWhiteSpace();
// use the next character to determine the type of filter
switch(getCurrentChar()) {
case AND_TOKEN:
if (debug) {System.out.println("SearchFilter: creating AND");}
filter = new CompoundFilter(true);
filter.parse();
break;
case OR_TOKEN:
if (debug) {System.out.println("SearchFilter: creating OR");}
filter = new CompoundFilter(false);
filter.parse();
break;
case NOT_TOKEN:
if (debug) {System.out.println("SearchFilter: creating OR");}
filter = new NotFilter();
filter.parse();
break;
default:
if (debug) {System.out.println("SearchFilter: creating SIMPLE");}
filter = new AtomicFilter();
filter.parse();
break;
}
skipWhiteSpace();
// make sure every filter ends with ")"
if(getCurrentChar() != END_FILTER_TOKEN) {
throw new InvalidSearchFilterException("expected \"" +
END_FILTER_TOKEN +
"\" at position " +
pos);
}
// skip past the ")"
this.consumeChar();
} catch (InvalidSearchFilterException e) {
if (debug) {System.out.println("rethrowing e");}
throw e; // just rethrow these
// catch all - any uncaught exception while parsing will end up here
} catch (Exception e) {
if(debug) {System.out.println(e.getMessage());e.printStackTrace();}
throw new InvalidSearchFilterException("Unable to parse " +
"character " + pos + " in \""+
this.filter + "\"");
}
return filter;
}
protected char getCurrentChar() {
return filter.charAt(pos);
}
protected char relCharAt(int i) {
return filter.charAt(pos + i);
}
protected void consumeChar() {
pos++;
}
protected void consumeChars(int i) {
pos += i;
}
protected int relIndexOf(int ch) {
return filter.indexOf(ch, pos) - pos;
}
protected String relSubstring(int beginIndex, int endIndex){
if(debug){System.out.println("relSubString: " + beginIndex +
" " + endIndex);}
return filter.substring(beginIndex+pos, endIndex+pos);
}
/**
* A class for dealing with compound filters ("and" & "or" filters).
*/
final class CompoundFilter implements StringFilter {
private Vector<StringFilter> subFilters;
private boolean polarity;
CompoundFilter(boolean polarity) {
subFilters = new Vector<>();
this.polarity = polarity;
}
public void parse() throws InvalidSearchFilterException {
SearchFilter.this.consumeChar(); // consume the "&"
while(SearchFilter.this.getCurrentChar() != END_FILTER_TOKEN) {
if (debug) {System.out.println("CompoundFilter: adding");}
StringFilter filter = SearchFilter.this.createNextFilter();
subFilters.addElement(filter);
skipWhiteSpace();
}
}
public boolean check(Attributes targetAttrs) throws NamingException {
for(int i = 0; i<subFilters.size(); i++) {
StringFilter filter = subFilters.elementAt(i);
if(filter.check(targetAttrs) != this.polarity) {
return !polarity;
}
}
return polarity;
}
} /* CompoundFilter */
/**
* A class for dealing with NOT filters
*/
final class NotFilter implements StringFilter {
private StringFilter filter;
public void parse() throws InvalidSearchFilterException {
SearchFilter.this.consumeChar(); // consume the "!"
filter = SearchFilter.this.createNextFilter();
}
public boolean check(Attributes targetAttrs) throws NamingException {
return !filter.check(targetAttrs);
}
} /* notFilter */
// note: declared here since member classes can't have static variables
static final int EQUAL_MATCH = 1;
static final int APPROX_MATCH = 2;
static final int GREATER_MATCH = 3;
static final int LESS_MATCH = 4;
/**
* A class for dealing wtih atomic filters
*/
final class AtomicFilter implements StringFilter {
private String attrID;
private String value;
private int matchType;
public void parse() throws InvalidSearchFilterException {
skipWhiteSpace();
try {
// find the end
int endPos = SearchFilter.this.relIndexOf(END_FILTER_TOKEN);
//determine the match type
int i = SearchFilter.this.relIndexOf(EQUAL_TOKEN);
if(debug) {System.out.println("AtomicFilter: = at " + i);}
int qualifier = SearchFilter.this.relCharAt(i-1);
switch(qualifier) {
case APPROX_TOKEN:
if (debug) {System.out.println("Atomic: APPROX found");}
matchType = APPROX_MATCH;
attrID = SearchFilter.this.relSubstring(0, i-1);
value = SearchFilter.this.relSubstring(i+1, endPos);
break;
case GREATER_TOKEN:
if (debug) {System.out.println("Atomic: GREATER found");}
matchType = GREATER_MATCH;
attrID = SearchFilter.this.relSubstring(0, i-1);
value = SearchFilter.this.relSubstring(i+1, endPos);
break;
case LESS_TOKEN:
if (debug) {System.out.println("Atomic: LESS found");}
matchType = LESS_MATCH;
attrID = SearchFilter.this.relSubstring(0, i-1);
value = SearchFilter.this.relSubstring(i+1, endPos);
break;
case EXTEND_TOKEN:
if(debug) {System.out.println("Atomic: EXTEND found");}
throw new OperationNotSupportedException("Extensible match not supported");
default:
if (debug) {System.out.println("Atomic: EQUAL found");}
matchType = EQUAL_MATCH;
attrID = SearchFilter.this.relSubstring(0,i);
value = SearchFilter.this.relSubstring(i+1, endPos);
break;
}
attrID = attrID.trim();
value = value.trim();
//update our position
SearchFilter.this.consumeChars(endPos);
} catch (Exception e) {
if (debug) {System.out.println(e.getMessage());
e.printStackTrace();}
InvalidSearchFilterException sfe =
new InvalidSearchFilterException("Unable to parse " +
"character " + SearchFilter.this.pos + " in \""+
SearchFilter.this.filter + "\"");
sfe.setRootCause(e);
throw(sfe);
}
if(debug) {System.out.println("AtomicFilter: " + attrID + "=" +
value);}
}
public boolean check(Attributes targetAttrs) {
Enumeration<?> candidates;
try {
Attribute attr = targetAttrs.get(attrID);
if(attr == null) {
return false;
}
candidates = attr.getAll();
} catch (NamingException ne) {
if (debug) {System.out.println("AtomicFilter: should never " +
"here");}
return false;
}
while(candidates.hasMoreElements()) {
String val = candidates.nextElement().toString();
if (debug) {System.out.println("Atomic: comparing: " + val);}
switch(matchType) {
case APPROX_MATCH:
case EQUAL_MATCH:
if(substringMatch(this.value, val)) {
if (debug) {System.out.println("Atomic: EQUAL match");}
return true;
}
break;
case GREATER_MATCH:
if (debug) {System.out.println("Atomic: GREATER match");}
if(val.compareTo(this.value) >= 0) {
return true;
}
break;
case LESS_MATCH:
if (debug) {System.out.println("Atomic: LESS match");}
if(val.compareTo(this.value) <= 0) {
return true;
}
break;
default:
if (debug) {System.out.println("AtomicFilter: unkown " +
"matchType");}
}
}
return false;
}
// used for substring comparisons (where proto has "*" wildcards
private boolean substringMatch(String proto, String value) {
// simple case 1: "*" means attribute presence is being tested
if(proto.equals(new Character(WILDCARD_TOKEN).toString())) {
if(debug) {System.out.println("simple presence assertion");}
return true;
}
// simple case 2: if there are no wildcards, call String.equals()
if(proto.indexOf(WILDCARD_TOKEN) == -1) {
return proto.equalsIgnoreCase(value);
}
if(debug) {System.out.println("doing substring comparison");}
// do the work: make sure all the substrings are present
int currentPos = 0;
StringTokenizer subStrs = new StringTokenizer(proto, "*", false);
// do we need to begin with the first token?
if(proto.charAt(0) != WILDCARD_TOKEN &&
!value.toLowerCase(Locale.ENGLISH).startsWith(
subStrs.nextToken().toLowerCase(Locale.ENGLISH))) {
if(debug) {
System.out.println("faild initial test");
}
return false;
}
while(subStrs.hasMoreTokens()) {
String currentStr = subStrs.nextToken();
if (debug) {System.out.println("looking for \"" +
currentStr +"\"");}
currentPos = value.toLowerCase(Locale.ENGLISH).indexOf(
currentStr.toLowerCase(Locale.ENGLISH), currentPos);
if(currentPos == -1) {
return false;
}
currentPos += currentStr.length();
}
// do we need to end with the last token?
if(proto.charAt(proto.length() - 1) != WILDCARD_TOKEN &&
currentPos != value.length() ) {
if(debug) {System.out.println("faild final test");}
return false;
}
return true;
}
} /* AtomicFilter */
// ----- static methods for producing string filters given attribute set
// ----- or object array
/**
* Creates an LDAP filter as a conjuction of the attributes supplied.
*/
public static String format(Attributes attrs) throws NamingException {
if (attrs == null || attrs.size() == 0) {
return "objectClass=*";
}
String answer;
answer = "(& ";
Attribute attr;
for (NamingEnumeration<? extends Attribute> e = attrs.getAll();
e.hasMore(); ) {
attr = e.next();
if (attr.size() == 0 || (attr.size() == 1 && attr.get() == null)) {
// only checking presence of attribute
answer += "(" + attr.getID() + "=" + "*)";
} else {
for (NamingEnumeration<?> ve = attr.getAll();
ve.hasMore(); ) {
String val = getEncodedStringRep(ve.next());
if (val != null) {
answer += "(" + attr.getID() + "=" + val + ")";
}
}
}
}
answer += ")";
//System.out.println("filter: " + answer);
return answer;
}
// Writes the hex representation of a byte to a StringBuffer.
private static void hexDigit(StringBuffer buf, byte x) {
char c;
c = (char) ((x >> 4) & 0xf);
if (c > 9)
c = (char) ((c-10) + 'A');
else
c = (char)(c + '0');
buf.append(c);
c = (char) (x & 0xf);
if (c > 9)
c = (char)((c-10) + 'A');
else
c = (char)(c + '0');
buf.append(c);
}
/**
* Returns the string representation of an object (such as an attr value).
* If obj is a byte array, encode each item as \xx, where xx is hex encoding
* of the byte value.
* Else, if obj is not a String, use its string representation (toString()).
* Special characters in obj (or its string representation) are then
* encoded appropriately according to RFC 2254.
* * \2a
* ( \28
* ) \29
* \ \5c
* NUL \00
*/
private static String getEncodedStringRep(Object obj) throws NamingException {
String str;
if (obj == null)
return null;
if (obj instanceof byte[]) {
// binary data must be encoded as \hh where hh is a hex char
byte[] bytes = (byte[])obj;
StringBuffer b1 = new StringBuffer(bytes.length*3);
for (int i = 0; i < bytes.length; i++) {
b1.append('\\');
hexDigit(b1, bytes[i]);
}
return b1.toString();
}
if (!(obj instanceof String)) {
str = obj.toString();
} else {
str = (String)obj;
}
int len = str.length();
StringBuffer buf = new StringBuffer(len);
char ch;
for (int i = 0; i < len; i++) {
switch (ch=str.charAt(i)) {
case '*':
buf.append("\\2a");
break;
case '(':
buf.append("\\28");
break;
case ')':
buf.append("\\29");
break;
case '\\':
buf.append("\\5c");
break;
case 0:
buf.append("\\00");
break;
default:
buf.append(ch);
}
}
return buf.toString();
}
/**
* Finds the first occurrence of <tt>ch</tt> in <tt>val</tt> starting
* from position <tt>start</tt>. It doesn't count if <tt>ch</tt>
* has been escaped by a backslash (\)
*/
public static int findUnescaped(char ch, String val, int start) {
int len = val.length();
while (start < len) {
int where = val.indexOf(ch, start);
// if at start of string, or not there at all, or if not escaped
if (where == start || where == -1 || val.charAt(where-1) != '\\')
return where;
// start search after escaped star
start = where + 1;
}
return -1;
}
/**
* Formats the expression <tt>expr</tt> using arguments from the array
* <tt>args</tt>.
*
* <code>{i}</code> specifies the <code>i</code>'th element from
* the array <code>args</code> is to be substituted for the
* string "<code>{i}</code>".
*
* To escape '{' or '}' (or any other character), use '\'.
*
* Uses getEncodedStringRep() to do encoding.
*/
public static String format(String expr, Object[] args)
throws NamingException {
int param;
int where = 0, start = 0;
StringBuffer answer = new StringBuffer(expr.length());
while ((where = findUnescaped('{', expr, start)) >= 0) {
int pstart = where + 1; // skip '{'
int pend = expr.indexOf('}', pstart);
if (pend < 0) {
throw new InvalidSearchFilterException("unbalanced {: " + expr);
}
// at this point, pend should be pointing at '}'
try {
param = Integer.parseInt(expr.substring(pstart, pend));
} catch (NumberFormatException e) {
throw new InvalidSearchFilterException(
"integer expected inside {}: " + expr);
}
if (param >= args.length) {
throw new InvalidSearchFilterException(
"number exceeds argument list: " + param);
}
answer.append(expr.substring(start, where)).append(getEncodedStringRep(args[param]));
start = pend + 1; // skip '}'
}
if (start < expr.length())
answer.append(expr.substring(start));
return answer.toString();
}
/*
* returns an Attributes instance containing only attributeIDs given in
* "attributeIDs" whose values come from the given DSContext.
*/
public static Attributes selectAttributes(Attributes originals,
String[] attrIDs) throws NamingException {
if (attrIDs == null)
return originals;
Attributes result = new BasicAttributes();
for(int i=0; i<attrIDs.length; i++) {
Attribute attr = originals.get(attrIDs[i]);
if(attr != null) {
result.put(attr);
}
}
return result;
}
/* For testing filter
public static void main(String[] args) {
Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
attrs.put("cn", "Rosanna Lee");
attrs.put("sn", "Lee");
attrs.put("fn", "Rosanna");
attrs.put("id", "10414");
attrs.put("machine", "jurassic");
try {
System.out.println(format(attrs));
String expr = "(&(Age = {0})(Account Balance <= {1}))";
Object[] fargs = new Object[2];
// fill in the parameters
fargs[0] = new Integer(65);
fargs[1] = new Float(5000);
System.out.println(format(expr, fargs));
System.out.println(format("bin={0}",
new Object[] {new byte[] {0, 1, 2, 3, 4, 5}}));
System.out.println(format("bin=\\{anything}", null));
} catch (NamingException e) {
e.printStackTrace();
}
}
*/
}

View File

@@ -0,0 +1,546 @@
/*
* Copyright (c) 1999, 2022, 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.url;
import javax.naming.*;
import javax.naming.spi.ResolveResult;
import javax.naming.spi.NamingManager;
import java.util.Hashtable;
import java.net.MalformedURLException;
import com.sun.jndi.toolkit.url.Uri.ParseMode;
/**
* This abstract class is a generic URL context that accepts as the
* name argument either a string URL or a Name whose first component
* is a URL. It resolves the URL to a target context and then continues
* the operation using the remaining name in the target context as if
* the first component names a junction.
*
* A subclass must define getRootURLContext()
* to process the URL into head/tail pieces. If it wants to control how
* URL strings are parsed and compared for the rename() operation, then
* it should override getNonRootURLSuffixes() and urlEquals().
*
* @author Scott Seligman
* @author Rosanna Lee
*/
abstract public class GenericURLContext implements Context {
protected Hashtable<String, Object> myEnv = null;
@SuppressWarnings("unchecked") // Expect Hashtable<String, Object>
public GenericURLContext(Hashtable<?,?> env) {
// context that is not tied to any specific URL
myEnv =
(Hashtable<String, Object>)(env == null ? null : env.clone());
}
public void close() throws NamingException {
myEnv = null;
}
public String getNameInNamespace() throws NamingException {
return ""; // %%% check this out: A URL context's name is ""
}
/**
* Resolves 'name' into a target context with remaining name.
* For example, with a JNDI URL "jndi://dnsname/rest_name",
* this method resolves "jndi://dnsname/" to a target context,
* and returns the target context with "rest_name".
* The definition of "root URL" and how much of the URL to
* consume is implementation specific.
* If rename() is supported for a particular URL scheme,
* getRootURLContext(), getURLPrefix(), and getURLSuffix()
* must be in sync wrt how URLs are parsed and returned.
*/
abstract protected ResolveResult getRootURLContext(String url,
Hashtable<?,?> env) throws NamingException;
/**
* Returns the suffix of the url. The result should be identical to
* that of calling getRootURLContext().getRemainingName(), but
* without the overhead of doing anything with the prefix like
* creating a context.
*<p>
* This method returns a Name instead of a String because to give
* the provider an opportunity to return a Name (for example,
* for weakly separated naming systems like COS naming).
*<p>
* The default implementation uses skips 'prefix', calls
* UrlUtil.decode() on it, and returns the result as a single component
* CompositeName.
* Subclass should override if this is not appropriate.
* This method is used only by rename().
* If rename() is supported for a particular URL scheme,
* getRootURLContext(), getURLPrefix(), and getURLSuffix()
* must be in sync wrt how URLs are parsed and returned.
*<p>
* For many URL schemes, this method is very similar to URL.getFile(),
* except getFile() will return a leading slash in the
* 2nd, 3rd, and 4th cases. For schemes like "ldap" and "iiop",
* the leading slash must be skipped before the name is an acceptable
* format for operation by the Context methods. For schemes that treat the
* leading slash as significant (such as "file"),
* the subclass must override getURLSuffix() to get the correct behavior.
* Remember, the behavior must match getRootURLContext().
*
* URL Suffix
* foo://host:port <empty string>
* foo://host:port/rest/of/name rest/of/name
* foo:///rest/of/name rest/of/name
* foo:/rest/of/name rest/of/name
* foo:rest/of/name rest/of/name
*/
protected Name getURLSuffix(String prefix, String url) throws NamingException {
String suffix = url.substring(prefix.length());
if (suffix.length() == 0) {
return new CompositeName();
}
if (suffix.charAt(0) == '/') {
suffix = suffix.substring(1); // skip leading slash
}
try {
return new CompositeName().add(UrlUtil.decode(suffix));
} catch (MalformedURLException e) {
throw new InvalidNameException(e.getMessage());
}
}
/**
* Finds the prefix of a URL.
* Default implementation looks for slashes and then extracts
* prefixes using String.substring().
* Subclass should override if this is not appropriate.
* This method is used only by rename().
* If rename() is supported for a particular URL scheme,
* getRootURLContext(), getURLPrefix(), and getURLSuffix()
* must be in sync wrt how URLs are parsed and returned.
*<p>
* URL Prefix
* foo://host:port foo://host:port
* foo://host:port/rest/of/name foo://host:port
* foo:///rest/of/name foo://
* foo:/rest/of/name foo:
* foo:rest/of/name foo:
*/
protected String getURLPrefix(String url) throws NamingException {
int start = url.indexOf(":");
if (start < 0) {
throw new OperationNotSupportedException("Invalid URL: " + url);
}
++start; // skip ':'
if (url.startsWith("//", start)) {
start += 2; // skip double slash
// find where the authority component ends
// and the rest of the URL starts
int slash = url.indexOf('/', start);
int qmark = url.indexOf('?', start);
int fmark = url.indexOf('#', start);
if (fmark > -1 && qmark > fmark) qmark = -1;
if (fmark > -1 && slash > fmark) slash = -1;
if (qmark > -1 && slash > qmark) slash = -1;
int posn = slash > -1 ? slash
: (qmark > -1 ? qmark
: (fmark > -1 ? fmark
: url.length()));
if (posn >= 0) {
start = posn;
} else {
start = url.length(); // rest of URL
}
}
// else 0 or 1 iniitial slashes; start is unchanged
return url.substring(0, start);
}
/**
* Determines whether two URLs are the same.
* Default implementation uses String.equals().
* Subclass should override if this is not appropriate.
* This method is used by rename().
*/
protected boolean urlEquals(String url1, String url2) {
return url1.equals(url2);
}
/**
* Gets the context in which to continue the operation. This method
* is called when this context is asked to process a multicomponent
* Name in which the first component is a URL.
* Treat the first component like a junction: resolve it and then use
* NamingManager.getContinuationContext() to get the target context in
* which to operate on the remainder of the name (n.getSuffix(1)).
*/
protected Context getContinuationContext(Name n) throws NamingException {
Object obj = lookup(n.get(0));
CannotProceedException cpe = new CannotProceedException();
cpe.setResolvedObj(obj);
cpe.setEnvironment(myEnv);
return NamingManager.getContinuationContext(cpe);
}
public Object lookup(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.lookup(res.getRemainingName());
} finally {
ctx.close();
}
}
public Object lookup(Name name) throws NamingException {
if (name.size() == 1) {
return lookup(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.lookup(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public void bind(String name, Object obj) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.bind(res.getRemainingName(), obj);
} finally {
ctx.close();
}
}
public void bind(Name name, Object obj) throws NamingException {
if (name.size() == 1) {
bind(name.get(0), obj);
} else {
Context ctx = getContinuationContext(name);
try {
ctx.bind(name.getSuffix(1), obj);
} finally {
ctx.close();
}
}
}
public void rebind(String name, Object obj) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.rebind(res.getRemainingName(), obj);
} finally {
ctx.close();
}
}
public void rebind(Name name, Object obj) throws NamingException {
if (name.size() == 1) {
rebind(name.get(0), obj);
} else {
Context ctx = getContinuationContext(name);
try {
ctx.rebind(name.getSuffix(1), obj);
} finally {
ctx.close();
}
}
}
public void unbind(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.unbind(res.getRemainingName());
} finally {
ctx.close();
}
}
public void unbind(Name name) throws NamingException {
if (name.size() == 1) {
unbind(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
ctx.unbind(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public void rename(String oldName, String newName) throws NamingException {
String oldPrefix = getURLPrefix(oldName);
String newPrefix = getURLPrefix(newName);
if (!urlEquals(oldPrefix, newPrefix)) {
throw new OperationNotSupportedException(
"Renaming using different URL prefixes not supported : " +
oldName + " " + newName);
}
ResolveResult res = getRootURLContext(oldName, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.rename(res.getRemainingName(), getURLSuffix(newPrefix, newName));
} finally {
ctx.close();
}
}
public void rename(Name name, Name newName) throws NamingException {
if (name.size() == 1) {
if (newName.size() != 1) {
throw new OperationNotSupportedException(
"Renaming to a Name with more components not supported: " + newName);
}
rename(name.get(0), newName.get(0));
} else {
// > 1 component with 1st one being URL
// URLs must be identical; cannot deal with diff URLs
if (!urlEquals(name.get(0), newName.get(0))) {
throw new OperationNotSupportedException(
"Renaming using different URLs as first components not supported: " +
name + " " + newName);
}
Context ctx = getContinuationContext(name);
try {
ctx.rename(name.getSuffix(1), newName.getSuffix(1));
} finally {
ctx.close();
}
}
}
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.list(res.getRemainingName());
} finally {
ctx.close();
}
}
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
if (name.size() == 1) {
return list(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.list(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public NamingEnumeration<Binding> listBindings(String name)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.listBindings(res.getRemainingName());
} finally {
ctx.close();
}
}
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
if (name.size() == 1) {
return listBindings(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.listBindings(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public void destroySubcontext(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
ctx.destroySubcontext(res.getRemainingName());
} finally {
ctx.close();
}
}
public void destroySubcontext(Name name) throws NamingException {
if (name.size() == 1) {
destroySubcontext(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
ctx.destroySubcontext(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public Context createSubcontext(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.createSubcontext(res.getRemainingName());
} finally {
ctx.close();
}
}
public Context createSubcontext(Name name) throws NamingException {
if (name.size() == 1) {
return createSubcontext(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.createSubcontext(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public Object lookupLink(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.lookupLink(res.getRemainingName());
} finally {
ctx.close();
}
}
public Object lookupLink(Name name) throws NamingException {
if (name.size() == 1) {
return lookupLink(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.lookupLink(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public NameParser getNameParser(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
Context ctx = (Context)res.getResolvedObj();
try {
return ctx.getNameParser(res.getRemainingName());
} finally {
ctx.close();
}
}
public NameParser getNameParser(Name name) throws NamingException {
if (name.size() == 1) {
return getNameParser(name.get(0));
} else {
Context ctx = getContinuationContext(name);
try {
return ctx.getNameParser(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public String composeName(String name, String prefix)
throws NamingException {
if (prefix.equals("")) {
return name;
} else if (name.equals("")) {
return prefix;
} else {
return (prefix + "/" + name);
}
}
public Name composeName(Name name, Name prefix) throws NamingException {
Name result = (Name)prefix.clone();
result.addAll(name);
return result;
}
public Object removeFromEnvironment(String propName)
throws NamingException {
if (myEnv == null) {
return null;
}
return myEnv.remove(propName);
}
public Object addToEnvironment(String propName, Object propVal)
throws NamingException {
if (myEnv == null) {
myEnv = new Hashtable<String, Object>(11, 0.75f);
}
return myEnv.put(propName, propVal);
}
@SuppressWarnings("unchecked") // clone()
public Hashtable<String, Object> getEnvironment() throws NamingException {
if (myEnv == null) {
return new Hashtable<>(5, 0.75f);
} else {
return (Hashtable<String, Object>)myEnv.clone();
}
}
/*
// To test, declare getURLPrefix and getURLSuffix static.
public static void main(String[] args) throws Exception {
String[] tests = {"file://host:port",
"file:///rest/of/name",
"file://host:port/rest/of/name",
"file:/rest/of/name",
"file:rest/of/name"};
for (int i = 0; i < tests.length; i++) {
String pre = getURLPrefix(tests[i]);
System.out.println(pre);
System.out.println(getURLSuffix(pre, tests[i]));
}
}
*/
}

View File

@@ -0,0 +1,411 @@
/*
* Copyright (c) 1999, 2011, 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.url;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.ResolveResult;
import javax.naming.spi.DirectoryManager;
import java.util.Hashtable;
/**
* This abstract class is a generic URL DirContext that accepts as the
* name argument either a string URL or a Name whose first component
* is a URL. It resolves the URL to a target context and then continues
* the operation using the remaining name in the target context as if
* the first component names a junction.
*
* A subclass must define getRootURLContext()
* to process the URL into head/tail pieces. If it wants to control how
* URL strings are parsed and compared for the rename() operation, then
* it should override getNonRootURLSuffixes() and urlEquals().
*
* @author Scott Seligman
* @author Rosanna Lee
*/
abstract public class GenericURLDirContext extends GenericURLContext
implements DirContext {
protected GenericURLDirContext(Hashtable<?,?> env) {
super(env);
}
/**
* Gets the context in which to continue the operation. This method
* is called when this context is asked to process a multicomponent
* Name in which the first component is a URL.
* Treat the first component like a junction: resolve it and then use
* DirectoryManager.getContinuationDirContext() to get the target context in
* which to operate on the remainder of the name (n.getSuffix(1)).
* Do this in case intermediate contexts are not DirContext.
*/
protected DirContext getContinuationDirContext(Name n) throws NamingException {
Object obj = lookup(n.get(0));
CannotProceedException cpe = new CannotProceedException();
cpe.setResolvedObj(obj);
cpe.setEnvironment(myEnv);
return DirectoryManager.getContinuationDirContext(cpe);
}
public Attributes getAttributes(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.getAttributes(res.getRemainingName());
} finally {
ctx.close();
}
}
public Attributes getAttributes(Name name) throws NamingException {
if (name.size() == 1) {
return getAttributes(name.get(0));
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.getAttributes(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public Attributes getAttributes(String name, String[] attrIds)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.getAttributes(res.getRemainingName(), attrIds);
} finally {
ctx.close();
}
}
public Attributes getAttributes(Name name, String[] attrIds)
throws NamingException {
if (name.size() == 1) {
return getAttributes(name.get(0), attrIds);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.getAttributes(name.getSuffix(1), attrIds);
} finally {
ctx.close();
}
}
}
public void modifyAttributes(String name, int mod_op, Attributes attrs)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
ctx.modifyAttributes(res.getRemainingName(), mod_op, attrs);
} finally {
ctx.close();
}
}
public void modifyAttributes(Name name, int mod_op, Attributes attrs)
throws NamingException {
if (name.size() == 1) {
modifyAttributes(name.get(0), mod_op, attrs);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
ctx.modifyAttributes(name.getSuffix(1), mod_op, attrs);
} finally {
ctx.close();
}
}
}
public void modifyAttributes(String name, ModificationItem[] mods)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
ctx.modifyAttributes(res.getRemainingName(), mods);
} finally {
ctx.close();
}
}
public void modifyAttributes(Name name, ModificationItem[] mods)
throws NamingException {
if (name.size() == 1) {
modifyAttributes(name.get(0), mods);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
ctx.modifyAttributes(name.getSuffix(1), mods);
} finally {
ctx.close();
}
}
}
public void bind(String name, Object obj, Attributes attrs)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
ctx.bind(res.getRemainingName(), obj, attrs);
} finally {
ctx.close();
}
}
public void bind(Name name, Object obj, Attributes attrs)
throws NamingException {
if (name.size() == 1) {
bind(name.get(0), obj, attrs);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
ctx.bind(name.getSuffix(1), obj, attrs);
} finally {
ctx.close();
}
}
}
public void rebind(String name, Object obj, Attributes attrs)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
ctx.rebind(res.getRemainingName(), obj, attrs);
} finally {
ctx.close();
}
}
public void rebind(Name name, Object obj, Attributes attrs)
throws NamingException {
if (name.size() == 1) {
rebind(name.get(0), obj, attrs);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
ctx.rebind(name.getSuffix(1), obj, attrs);
} finally {
ctx.close();
}
}
}
public DirContext createSubcontext(String name, Attributes attrs)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.createSubcontext(res.getRemainingName(), attrs);
} finally {
ctx.close();
}
}
public DirContext createSubcontext(Name name, Attributes attrs)
throws NamingException {
if (name.size() == 1) {
return createSubcontext(name.get(0), attrs);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.createSubcontext(name.getSuffix(1), attrs);
} finally {
ctx.close();
}
}
}
public DirContext getSchema(String name) throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
return ctx.getSchema(res.getRemainingName());
}
public DirContext getSchema(Name name) throws NamingException {
if (name.size() == 1) {
return getSchema(name.get(0));
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.getSchema(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public DirContext getSchemaClassDefinition(String name)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.getSchemaClassDefinition(res.getRemainingName());
} finally {
ctx.close();
}
}
public DirContext getSchemaClassDefinition(Name name)
throws NamingException {
if (name.size() == 1) {
return getSchemaClassDefinition(name.get(0));
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.getSchemaClassDefinition(name.getSuffix(1));
} finally {
ctx.close();
}
}
}
public NamingEnumeration<SearchResult> search(String name,
Attributes matchingAttributes)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.search(res.getRemainingName(), matchingAttributes);
} finally {
ctx.close();
}
}
public NamingEnumeration<SearchResult> search(Name name,
Attributes matchingAttributes)
throws NamingException {
if (name.size() == 1) {
return search(name.get(0), matchingAttributes);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.search(name.getSuffix(1), matchingAttributes);
} finally {
ctx.close();
}
}
}
public NamingEnumeration<SearchResult> search(String name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.search(res.getRemainingName(),
matchingAttributes, attributesToReturn);
} finally {
ctx.close();
}
}
public NamingEnumeration<SearchResult> search(Name name,
Attributes matchingAttributes,
String[] attributesToReturn)
throws NamingException {
if (name.size() == 1) {
return search(name.get(0), matchingAttributes,
attributesToReturn);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.search(name.getSuffix(1),
matchingAttributes, attributesToReturn);
} finally {
ctx.close();
}
}
}
public NamingEnumeration<SearchResult> search(String name,
String filter,
SearchControls cons)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return ctx.search(res.getRemainingName(), filter, cons);
} finally {
ctx.close();
}
}
public NamingEnumeration<SearchResult> search(Name name,
String filter,
SearchControls cons)
throws NamingException {
if (name.size() == 1) {
return search(name.get(0), filter, cons);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.search(name.getSuffix(1), filter, cons);
} finally {
ctx.close();
}
}
}
public NamingEnumeration<SearchResult> search(String name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException {
ResolveResult res = getRootURLContext(name, myEnv);
DirContext ctx = (DirContext)res.getResolvedObj();
try {
return
ctx.search(res.getRemainingName(), filterExpr, filterArgs, cons);
} finally {
ctx.close();
}
}
public NamingEnumeration<SearchResult> search(Name name,
String filterExpr,
Object[] filterArgs,
SearchControls cons)
throws NamingException {
if (name.size() == 1) {
return search(name.get(0), filterExpr, filterArgs, cons);
} else {
DirContext ctx = getContinuationDirContext(name);
try {
return ctx.search(name.getSuffix(1), filterExpr, filterArgs, cons);
} finally {
ctx.close();
}
}
}
}

View File

@@ -0,0 +1,525 @@
/*
* Copyright (c) 2000, 2022, 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.url;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* A Uri object represents an absolute Uniform Resource Identifier
* (URI) as defined by RFC 2396 and updated by RFC 2373 and RFC 2732.
* The most commonly used form of URI is the Uniform Resource Locator (URL).
*
* <p> The java.net.URL class cannot be used to parse URIs since it
* requires the installation of URL stream handlers that may not be
* available.
*
* <p> The {@linkplain ParseMode#STRICT strict} parsing mode uses
* the java.net.URI class to syntactically validate URI strings.
* The {@linkplain ParseMode#COMPAT compat} mode validate the
* URI authority and rejects URI fragments, but doesn't perform any
* additional validation on path and query, other than that
* which may be implemented in the concrete the Uri subclasses.
* The {@linkplain ParseMode#LEGACY legacy} mode should not be
* used unless the application is capable of validating all URI
* strings before any constructors of this class is invoked.
*
* <p> The format of an absolute URI (see the RFCs mentioned above) is:
* <p><blockquote><pre>
* absoluteURI = scheme ":" ( hier_part | opaque_part )
*
* scheme = alpha *( alpha | digit | "+" | "-" | "." )
*
* hier_part = ( net_path | abs_path ) [ "?" query ]
* opaque_part = uric_no_slash *uric
*
* net_path = "//" authority [ abs_path ]
* abs_path = "/" path_segments
*
* authority = server | reg_name
* reg_name = 1*( unreserved | escaped | "$" | "," |
* ";" | ":" | "@" | "&" | "=" | "+" )
* server = [ [ userinfo "@" ] hostport ]
* userinfo = *( unreserved | escaped |
* ";" | ":" | "&" | "=" | "+" | "$" | "," )
*
* hostport = host [ ":" port ]
* host = hostname | IPv4address | IPv6reference
* port = *digit
*
* IPv6reference = "[" IPv6address "]"
* IPv6address = hexpart [ ":" IPv4address ]
* IPv4address = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
* hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
* hexseq = hex4 *( ":" hex4)
* hex4 = 1*4hex
*
* path = [ abs_path | opaque_part ]
* path_segments = segment *( "/" segment )
* segment = *pchar *( ";" param )
* param = *pchar
* pchar = unreserved | escaped |
* ":" | "@" | "&" | "=" | "+" | "$" | ","
*
* query = *uric
*
* uric = reserved | unreserved | escaped
* uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
* "&" | "=" | "+" | "$" | ","
* reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
* "$" | "," | "[" | "]"
* unreserved = alphanum | mark
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
* escaped = "%" hex hex
* unwise = "{" | "}" | "|" | "\" | "^" | "`"
* </pre></blockquote>
*
* <p> Currently URIs containing <tt>userinfo</tt> or <tt>reg_name</tt>
* are not supported.
* The <tt>opaque_part</tt> of a non-hierarchical URI is treated as if
* if were a <tt>path</tt> without a leading slash.
*/
public class Uri {
// three parsing modes
public enum ParseMode {
/**
* Strict validation mode.
* Validate the URI syntactically using {@link java.net.URI}.
* Rejects URI fragments unless explicitly supported by the
* subclass.
*/
STRICT,
/**
* Compatibility mode. The URI authority is syntactically validated.
* Rejects URI fragments unless explicitly supported by the
* subclass.
* This is the default.
*/
COMPAT,
/**
* Legacy mode. In this mode, no validation is performed.
*/
LEGACY
}
protected String uri;
protected String scheme;
protected String host = null;
protected int port = -1;
protected boolean hasAuthority;
protected String path;
protected String query = null;
protected String fragment;
/**
* Creates a Uri object given a URI string.
*/
public Uri(String uri) throws MalformedURLException {
init(uri);
}
/**
* Creates an uninitialized Uri object. The init() method must
* be called before any other Uri methods.
*/
protected Uri() {
}
/**
* The parse mode for parsing this URI.
* The default is {@link ParseMode#COMPAT}.
* @return the parse mode for parsing this URI.
*/
protected ParseMode parseMode() {
return ParseMode.COMPAT;
}
/**
* Initializes a Uri object given a URI string.
* This method must be called exactly once, and before any other Uri
* methods.
*/
protected void init(String uri) throws MalformedURLException {
this.uri = uri;
parse(uri, parseMode());
}
/**
* Returns the URI's scheme.
*/
public String getScheme() {
return scheme;
}
/**
* Returns the host from the URI's authority part, or null
* if no host is provided. If the host is an IPv6 literal, the
* delimiting brackets are part of the returned value (see
* {@link java.net.URI#getHost}).
*/
public String getHost() {
return host;
}
/**
* Returns the port from the URI's authority part, or -1 if
* no port is provided.
*/
public int getPort() {
return port;
}
/**
* Returns the URI's path. The path is never null. Note that a
* slash following the authority part (or the scheme if there is
* no authority part) is part of the path. For example, the path
* of "http://host/a/b" is "/a/b".
*/
public String getPath() {
return path;
}
/**
* Returns the URI's query part, or null if no query is provided.
* Note that a query always begins with a leading "?".
*/
public String getQuery() {
return query;
}
/**
* Returns the URI as a string.
*/
public String toString() {
return uri;
}
private void parse(String uri, ParseMode mode) throws MalformedURLException {
switch (mode) {
case STRICT:
parseStrict(uri);
break;
case COMPAT:
parseCompat(uri);
break;
case LEGACY:
parseLegacy(uri);
break;
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Use java.net.URI to validate the uri string syntax
*/
private void parseStrict(String uri) throws MalformedURLException {
try {
if (!isSchemeOnly(uri)) {
URI u = new URI(uri);
scheme = u.getScheme();
if (scheme == null) throw new MalformedURLException("Invalid URI: " + uri);
String auth = u.getRawAuthority();
hasAuthority = auth != null;
if (hasAuthority) {
String host = u.getHost();
int port = u.getPort();
if (host != null) this.host = host;
if (port != -1) this.port = port;
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : (":" + port));
if (!hostport.equals(auth)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
}
path = u.getRawPath();
if (u.getRawQuery() != null) {
query = "?" + u.getRawQuery();
}
if (u.getRawFragment() != null) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
fragment = "#" + u.getRawFragment();
}
} else {
// scheme-only URIs are not supported by java.net.URI
// validate the URI by appending "/" to the uri string.
String s = uri.substring(0, uri.indexOf(':'));
URI u = new URI(uri + "/");
if (!s.equals(u.getScheme())
|| !checkSchemeOnly(uri, u.getScheme())) {
throw newInvalidURISchemeException(uri);
}
scheme = s;
path = "";
}
} catch (URISyntaxException e) {
MalformedURLException mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Compatibility mode. Use java.net.URI to validate the syntax of
* the uri string authority.
*/
private void parseCompat(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme
int slash = uri.indexOf('/');
int qmark = uri.indexOf('?');
int fmark = uri.indexOf('#');
if (i < 0 || slash > 0 && i > slash || qmark > 0 && i > qmark || fmark > 0 && i > fmark) {
throw new MalformedURLException("Invalid URI: " + uri);
}
if (fmark > -1) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
}
if (i == uri.length() - 1) {
if (!isSchemeOnly(uri)) {
throw newInvalidURISchemeException(uri);
}
}
scheme = uri.substring(0, i);
i++; // skip past ":"
hasAuthority = uri.startsWith("//", i);
if (fmark > -1 && qmark > fmark) qmark = -1;
int endp = qmark > -1 ? qmark : fmark > -1 ? fmark : uri.length();
if (hasAuthority) { // parse "//host:port"
i += 2; // skip past "//"
int starta = i;
// authority ends at the first appearance of /, ?, or #
int enda = uri.indexOf('/', i);
if (enda == -1 || qmark > -1 && qmark < enda) enda = qmark;
if (enda == -1 || fmark > -1 && fmark < enda) enda = fmark;
if (enda < 0) {
enda = uri.length();
}
if (uri.startsWith(":", i)) {
// LdapURL supports empty host.
i++;
host = "";
if (enda > i) {
port = Integer.parseInt(uri.substring(i, enda));
}
} else {
// Use URI to parse authority
try {
// URI requires at least one char after authority:
// we use "/" and expect that the resulting URI path
// will be exactly "/".
URI u = new URI(uri.substring(0, enda) + "/");
String auth = uri.substring(starta, enda);
host = u.getHost();
port = u.getPort();
String p = u.getRawPath();
String q = u.getRawQuery();
String f = u.getRawFragment();
String ui = u.getRawUserInfo();
if (ui != null) {
throw new MalformedURLException("user info not supported in authority: " + ui);
}
if (!"/".equals(p)) {
throw new MalformedURLException("invalid authority: " + auth);
}
if (q != null) {
throw new MalformedURLException("invalid trailing characters in authority: ?" + q);
}
if (f != null) {
throw new MalformedURLException("invalid trailing characters in authority: #" + f);
}
String hostport = (host == null ? "" : host)
+ (port == -1?"":(":" + port));
if (!auth.equals(hostport)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
} catch (URISyntaxException e) {
MalformedURLException mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
i = enda;
}
path = uri.substring(i, endp);
// look for query
if (qmark > -1) {
if (fmark > -1) {
query = uri.substring(qmark, fmark);
} else {
query = uri.substring(qmark);
}
}
if (fmark > -1) {
fragment = uri.substring(fmark);
}
}
/**
* A subclass of {@code Uri} that supports scheme only
* URIs can override this method and return true in the
* case where the URI string is a scheme-only URI that
* the subclass supports.
* @implSpec
* The default implementation of this method returns false,
* always.
* @param uri An URI string
* @return if this is a scheme-only URI supported by the subclass
*/
protected boolean isSchemeOnly(String uri) {
return false;
}
/**
* Checks whether the given uri string should be considered
* as a scheme-only URI. For some protocols - e.g. DNS, we
* might accept "dns://" as a valid URL denoting default DNS.
* For others - we might only accept "scheme:".
* @implSpec
* The default implementation of this method returns true if
* the URI is of the form {@code "<scheme>:"} with nothing
* after the scheme delimiter.
* @param uri the URI
* @param scheme the scheme
* @return true if the URI should be considered as a scheme-only
* URI supported by this URI scheme.
*/
protected boolean checkSchemeOnly(String uri, String scheme) {
return uri.equals(scheme + ":");
}
/**
* Creates a {@code MalformedURLException} to be thrown when the
* URI scheme is not supported.
*
* @param uri the URI string
* @return a {@link MalformedURLException}
*/
protected MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException("Invalid URI scheme: " + uri);
}
/**
* Whether fragments are supported.
* @implSpec
* The default implementation of this method retturns false, always.
* @return true if fragments are supported.
*/
protected boolean acceptsFragment() {
return parseMode() == ParseMode.LEGACY;
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Legacy parsing mode.
*/
private void parseLegacy(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme
if (i < 0) {
throw new MalformedURLException("Invalid URI: " + uri);
}
scheme = uri.substring(0, i);
i++; // skip past ":"
hasAuthority = uri.startsWith("//", i);
if (hasAuthority) { // parse "//host:port"
i += 2; // skip past "//"
int slash = uri.indexOf('/', i);
if (slash < 0) {
slash = uri.length();
}
if (uri.startsWith("[", i)) { // at IPv6 literal
int brac = uri.indexOf(']', i + 1);
if (brac < 0 || brac > slash) {
throw new MalformedURLException("Invalid URI: " + uri);
}
host = uri.substring(i, brac + 1); // include brackets
i = brac + 1; // skip past "[...]"
} else { // at host name or IPv4
int colon = uri.indexOf(':', i);
int hostEnd = (colon < 0 || colon > slash)
? slash
: colon;
if (i < hostEnd) {
host = uri.substring(i, hostEnd);
}
i = hostEnd; // skip past host
}
if ((i + 1 < slash) &&
uri.startsWith(":", i)) { // parse port
i++; // skip past ":"
port = Integer.parseInt(uri.substring(i, slash));
}
i = slash; // skip to path
}
int qmark = uri.indexOf('?', i); // look for query
if (qmark < 0) {
path = uri.substring(i);
} else {
path = uri.substring(i, qmark);
query = uri.substring(qmark);
}
}
/*
// Debug
public static void main(String args[]) throws MalformedURLException {
for (int i = 0; i < args.length; i++) {
Uri uri = new Uri(args[i]);
String h = (uri.getHost() != null) ? uri.getHost() : "";
String p = (uri.getPort() != -1) ? (":" + uri.getPort()) : "";
String a = uri.hasAuthority ? ("//" + h + p) : "";
String q = (uri.getQuery() != null) ? uri.getQuery() : "";
String str = uri.getScheme() + ":" + a + uri.getPath() + q;
if (! uri.toString().equals(str)) {
System.out.println(str);
}
System.out.println(h);
}
}
*/
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 1999, 2012, 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.url;
import java.net.MalformedURLException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
/**
* Utilities for dealing with URLs.
* @author Vincent Ryan
*/
final public class UrlUtil {
// To prevent creation of this static class
private UrlUtil() {
}
/**
* Decode a URI string (according to RFC 2396).
*/
public static final String decode(String s) throws MalformedURLException {
try {
return decode(s, "8859_1");
} catch (UnsupportedEncodingException e) {
// ISO-Latin-1 should always be available?
throw new MalformedURLException("ISO-Latin-1 decoder unavailable");
}
}
/**
* Decode a URI string (according to RFC 2396).
*
* Three-character sequences '%xy', where 'xy' is the two-digit
* hexadecimal representation of the lower 8-bits of a character,
* are decoded into the character itself.
*
* The string is subsequently converted using the specified encoding
*/
public static final String decode(String s, String enc)
throws MalformedURLException, UnsupportedEncodingException {
try {
return URLDecoder.decode(s, enc);
} catch (IllegalArgumentException iae) {
MalformedURLException mue = new MalformedURLException("Invalid URI encoding: " + s);
mue.initCause(iae);
throw mue;
}
}
/**
* Encode a string for inclusion in a URI (according to RFC 2396).
*
* Unsafe characters are escaped by encoding them in three-character
* sequences '%xy', where 'xy' is the two-digit hexadecimal representation
* of the lower 8-bits of the character.
*
* The question mark '?' character is also escaped, as required by RFC 2255.
*
* The string is first converted to the specified encoding.
* For LDAP (2255), the encoding must be UTF-8.
*/
public static final String encode(String s, String enc)
throws UnsupportedEncodingException {
byte[] bytes = s.getBytes(enc);
int count = bytes.length;
/*
* From RFC 2396:
*
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
* reserved = ";" | "/" | ":" | "?" | "@" | "&" | "=" | "+" | "$" | ","
*/
final String allowed = "=,+;.'-@&/$_()!~*:"; // '?' is omitted
char[] buf = new char[3 * count];
int j = 0;
for (int i = 0; i < count; i++) {
if ((bytes[i] >= 0x61 && bytes[i] <= 0x7A) || // a..z
(bytes[i] >= 0x41 && bytes[i] <= 0x5A) || // A..Z
(bytes[i] >= 0x30 && bytes[i] <= 0x39) || // 0..9
(allowed.indexOf(bytes[i]) >= 0)) {
buf[j++] = (char) bytes[i];
} else {
buf[j++] = '%';
buf[j++] = Character.forDigit(0xF & (bytes[i] >>> 4), 16);
buf[j++] = Character.forDigit(0xF & bytes[i], 16);
}
}
return new String(buf, 0, j);
}
}