feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
240
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNBindingEnumeration.java
Normal file
240
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNBindingEnumeration.java
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.spi.NamingManager;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.omg.CosNaming.*;
|
||||
|
||||
import com.sun.jndi.toolkit.corba.CorbaUtils;
|
||||
|
||||
/**
|
||||
* Implements the JNDI NamingEnumeration interface for COS
|
||||
* Naming. Gets hold of a list of bindings from the COS Naming Server
|
||||
* and allows the client to iterate through them.
|
||||
*
|
||||
* @author Raj Krishnamurthy
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final class CNBindingEnumeration
|
||||
implements NamingEnumeration<javax.naming.Binding> {
|
||||
|
||||
private static final int DEFAULT_BATCHSIZE = 100;
|
||||
private BindingListHolder _bindingList; // list of bindings
|
||||
private BindingIterator _bindingIter; // iterator for getting list of bindings
|
||||
private int counter; // pointer in _bindingList
|
||||
private int batchsize = DEFAULT_BATCHSIZE; // how many to ask for each time
|
||||
private CNCtx _ctx; // ctx to list
|
||||
private Hashtable<?,?> _env; // environment for getObjectInstance
|
||||
private boolean more = false; // iterator done?
|
||||
private boolean isLookedUpCtx = false; // iterating on a context beneath this context ?
|
||||
|
||||
/**
|
||||
* Creates a CNBindingEnumeration object.
|
||||
* @param ctx Context to enumerate
|
||||
*/
|
||||
CNBindingEnumeration(CNCtx ctx, boolean isLookedUpCtx, Hashtable<?,?> env) {
|
||||
// Get batch size to use
|
||||
String batch = (env != null ?
|
||||
(String)env.get(javax.naming.Context.BATCHSIZE) : null);
|
||||
if (batch != null) {
|
||||
try {
|
||||
batchsize = Integer.parseInt(batch);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Batch size not numeric: " + batch);
|
||||
}
|
||||
}
|
||||
_ctx = ctx;
|
||||
_ctx.incEnumCount();
|
||||
this.isLookedUpCtx = isLookedUpCtx;
|
||||
_env = env;
|
||||
_bindingList = new BindingListHolder();
|
||||
BindingIteratorHolder _bindingIterH = new BindingIteratorHolder();
|
||||
|
||||
// Perform listing and request that bindings be returned in _bindingIter
|
||||
// Upon return,_bindingList returns a zero length list
|
||||
_ctx._nc.list(0, _bindingList, _bindingIterH);
|
||||
|
||||
_bindingIter = _bindingIterH.value;
|
||||
|
||||
// Get first batch using _bindingIter
|
||||
if (_bindingIter != null) {
|
||||
more = _bindingIter.next_n(batchsize, _bindingList);
|
||||
} else {
|
||||
more = false;
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next binding in the list.
|
||||
* @exception NamingException any naming exception.
|
||||
*/
|
||||
|
||||
public javax.naming.Binding next() throws NamingException {
|
||||
if (more && counter >= _bindingList.value.length) {
|
||||
getMore();
|
||||
}
|
||||
if (more && counter < _bindingList.value.length) {
|
||||
org.omg.CosNaming.Binding bndg = _bindingList.value[counter];
|
||||
counter++;
|
||||
return mapBinding(bndg);
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true or false depending on whether there are more bindings.
|
||||
* @return boolean value
|
||||
*/
|
||||
|
||||
public boolean hasMore() throws NamingException {
|
||||
// If there's more, check whether current bindingList has been exhausted,
|
||||
// and if so, try to get more.
|
||||
// If no more, just say so.
|
||||
return more ? (counter < _bindingList.value.length || getMore()) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false depending on whether there are more bindings.
|
||||
* Need to define this to satisfy the Enumeration api requirement.
|
||||
* @return boolean value
|
||||
*/
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
try {
|
||||
return hasMore();
|
||||
} catch (NamingException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next binding in the list.
|
||||
* @exception NoSuchElementException Thrown when the end of the
|
||||
* list is reached.
|
||||
*/
|
||||
|
||||
public javax.naming.Binding nextElement() {
|
||||
try {
|
||||
return next();
|
||||
} catch (NamingException ne) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws NamingException {
|
||||
more = false;
|
||||
if (_bindingIter != null) {
|
||||
_bindingIter.destroy();
|
||||
_bindingIter = null;
|
||||
}
|
||||
if (_ctx != null) {
|
||||
_ctx.decEnumCount();
|
||||
|
||||
/**
|
||||
* context was obtained by CNCtx, the user doesn't have a handle to
|
||||
* it, close it as we are done enumerating through the context
|
||||
*/
|
||||
if (isLookedUpCtx) {
|
||||
_ctx.close();
|
||||
}
|
||||
_ctx = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
try {
|
||||
close();
|
||||
} catch (NamingException e) {
|
||||
// ignore failures
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next batch using _bindingIter. Update the 'more' field.
|
||||
*/
|
||||
private boolean getMore() throws NamingException {
|
||||
try {
|
||||
more = _bindingIter.next_n(batchsize, _bindingList);
|
||||
counter = 0; // reset
|
||||
} catch (Exception e) {
|
||||
more = false;
|
||||
NamingException ne = new NamingException(
|
||||
"Problem getting binding list");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
return more;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JNDI Binding object from the COS Naming binding
|
||||
* object.
|
||||
* @exception NameNotFound No objects under the name.
|
||||
* @exception CannotProceed Unable to obtain a continuation context
|
||||
* @exception InvalidName Name not understood.
|
||||
* @exception NamingException One of the above.
|
||||
*/
|
||||
|
||||
private javax.naming.Binding mapBinding(org.omg.CosNaming.Binding bndg)
|
||||
throws NamingException {
|
||||
java.lang.Object obj = _ctx.callResolve(bndg.binding_name);
|
||||
|
||||
Name cname = CNNameParser.cosNameToName(bndg.binding_name);
|
||||
|
||||
try {
|
||||
// Check whether object factory codebase is trusted
|
||||
if (CorbaUtils.isObjectFactoryTrusted(obj)) {
|
||||
obj = NamingManager.getObjectInstance(obj, cname, _ctx, _env);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
NamingException ne = new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// Use cname.toString() instead of bindingName because the name
|
||||
// in the binding should be a composite name
|
||||
String cnameStr = cname.toString();
|
||||
javax.naming.Binding jbndg = new javax.naming.Binding(cnameStr, obj);
|
||||
|
||||
NameComponent[] comps = _ctx.makeFullName(bndg.binding_name);
|
||||
String fullName = CNNameParser.cosNameToInsString(comps);
|
||||
jbndg.setNameInNamespace(fullName);
|
||||
return jbndg;
|
||||
}
|
||||
}
|
||||
1178
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNCtx.java
Normal file
1178
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNCtx.java
Normal file
File diff suppressed because it is too large
Load Diff
51
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNCtxFactory.java
Normal file
51
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNCtxFactory.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.spi.InitialContextFactory;
|
||||
import javax.naming.*;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Implements the JNDI SPI InitialContextFactory interface used to
|
||||
* create the InitialContext objects.
|
||||
*
|
||||
* @author Raj Krishnamurthy
|
||||
*/
|
||||
|
||||
public class CNCtxFactory implements InitialContextFactory {
|
||||
|
||||
/**
|
||||
* Creates the InitialContext object. Properties parameter should
|
||||
* should contain the ORB object for the value jndi.corba.orb.
|
||||
* @param env Properties object
|
||||
*/
|
||||
|
||||
public Context getInitialContext(Hashtable<?,?> env) throws NamingException {
|
||||
return new CNCtx(env);
|
||||
}
|
||||
}
|
||||
500
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNNameParser.java
Normal file
500
jdkSrc/jdk8/com/sun/jndi/cosnaming/CNNameParser.java
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.*;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.omg.CosNaming.NameComponent;
|
||||
|
||||
/**
|
||||
* Parsing routines for NameParser as well as COS Naming stringified names.
|
||||
* This is used by CNCtx to create a NameComponent[] object and vice versa.
|
||||
* It follows Section 4.5 of Interoperable Naming Service (INS) 98-10-11.
|
||||
* In summary, the stringified form is a left-to-right, forward-slash
|
||||
* separated name. id and kinds are separated by '.'. backslash is the
|
||||
* escape character.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final public class CNNameParser implements NameParser {
|
||||
|
||||
private static final Properties mySyntax = new Properties();
|
||||
private static final char kindSeparator = '.';
|
||||
private static final char compSeparator = '/';
|
||||
private static final char escapeChar = '\\';
|
||||
static {
|
||||
mySyntax.put("jndi.syntax.direction", "left_to_right");
|
||||
mySyntax.put("jndi.syntax.separator", ""+compSeparator);
|
||||
mySyntax.put("jndi.syntax.escape", ""+escapeChar);
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new name parser for parsing names in INS syntax.
|
||||
*/
|
||||
public CNNameParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CompoundName given a string in INS syntax.
|
||||
* @param name The non-null string representation of the name.
|
||||
* @return a non-null CompoundName
|
||||
*/
|
||||
public Name parse(String name) throws NamingException {
|
||||
Vector<String> comps = insStringToStringifiedComps(name);
|
||||
return new CNCompoundName(comps.elements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NameComponent[] from a Name structure.
|
||||
* Used by CNCtx to convert the input Name arg into a NameComponent[].
|
||||
* @param a CompoundName or a CompositeName;
|
||||
* each component must be the stringified form of a NameComponent.
|
||||
*/
|
||||
static NameComponent[] nameToCosName(Name name)
|
||||
throws InvalidNameException {
|
||||
int len = name.size();
|
||||
if (len == 0) {
|
||||
return new NameComponent[0];
|
||||
}
|
||||
|
||||
NameComponent[] answer = new NameComponent[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
answer[i] = parseComponent(name.get(i));
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the INS stringified form of a NameComponent[].
|
||||
* Used by CNCtx.getNameInNamespace(), CNCompoundName.toString().
|
||||
*/
|
||||
static String cosNameToInsString(NameComponent[] cname) {
|
||||
StringBuffer str = new StringBuffer();
|
||||
for ( int i = 0; i < cname.length; i++) {
|
||||
if ( i > 0) {
|
||||
str.append(compSeparator);
|
||||
}
|
||||
str.append(stringifyComponent(cname[i]));
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CompositeName from a NameComponent[].
|
||||
* Used by ExceptionMapper and CNBindingEnumeration to convert
|
||||
* a NameComponent[] into a composite name.
|
||||
*/
|
||||
static Name cosNameToName(NameComponent[] cname) {
|
||||
Name nm = new CompositeName();
|
||||
for ( int i = 0; cname != null && i < cname.length; i++) {
|
||||
try {
|
||||
nm.add(stringifyComponent(cname[i]));
|
||||
} catch (InvalidNameException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return nm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an INS-syntax string name into a Vector in which
|
||||
* each element of the vector contains a stringified form of
|
||||
* a NameComponent.
|
||||
*/
|
||||
private static Vector<String> insStringToStringifiedComps(String str)
|
||||
throws InvalidNameException {
|
||||
|
||||
int len = str.length();
|
||||
Vector<String> components = new Vector<>(10);
|
||||
char[] id = new char[len];
|
||||
char[] kind = new char[len];
|
||||
int idCount, kindCount;
|
||||
boolean idMode;
|
||||
for (int i = 0; i < len; ) {
|
||||
idCount = kindCount = 0; // reset for new component
|
||||
idMode = true; // always start off parsing id
|
||||
while (i < len) {
|
||||
if (str.charAt(i) == compSeparator) {
|
||||
break;
|
||||
|
||||
} else if (str.charAt(i) == escapeChar) {
|
||||
if (i + 1 >= len) {
|
||||
throw new InvalidNameException(str +
|
||||
": unescaped \\ at end of component");
|
||||
} else if (isMeta(str.charAt(i+1))) {
|
||||
++i; // skip escape and let meta through
|
||||
if (idMode) {
|
||||
id[idCount++] = str.charAt(i++);
|
||||
} else {
|
||||
kind[kindCount++] = str.charAt(i++);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidNameException(str +
|
||||
": invalid character being escaped");
|
||||
}
|
||||
|
||||
} else if (idMode && str.charAt(i) == kindSeparator) {
|
||||
// just look for the first kindSeparator
|
||||
++i; // skip kind separator
|
||||
idMode = false;
|
||||
|
||||
} else {
|
||||
if (idMode) {
|
||||
id[idCount++] = str.charAt(i++);
|
||||
} else {
|
||||
kind[kindCount++] = str.charAt(i++);
|
||||
}
|
||||
}
|
||||
}
|
||||
components.addElement(stringifyComponent(
|
||||
new NameComponent(new String(id, 0, idCount),
|
||||
new String(kind, 0, kindCount))));
|
||||
|
||||
if (i < len) {
|
||||
++i; // skip separator
|
||||
}
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a NameComponent given its stringified form.
|
||||
*/
|
||||
private static NameComponent parseComponent(String compStr)
|
||||
throws InvalidNameException {
|
||||
NameComponent comp = new NameComponent();
|
||||
int kindSep = -1;
|
||||
int len = compStr.length();
|
||||
|
||||
int j = 0;
|
||||
char[] newStr = new char[len];
|
||||
boolean escaped = false;
|
||||
|
||||
// Find the kind separator
|
||||
for (int i = 0; i < len && kindSep < 0; i++) {
|
||||
if (escaped) {
|
||||
newStr[j++] = compStr.charAt(i);
|
||||
escaped = false;
|
||||
} else if (compStr.charAt(i) == escapeChar) {
|
||||
if (i + 1 >= len) {
|
||||
throw new InvalidNameException(compStr +
|
||||
": unescaped \\ at end of component");
|
||||
} else if (isMeta(compStr.charAt(i+1))) {
|
||||
escaped = true;
|
||||
} else {
|
||||
throw new InvalidNameException(compStr +
|
||||
": invalid character being escaped");
|
||||
}
|
||||
} else if (compStr.charAt(i) == kindSeparator) {
|
||||
kindSep = i;
|
||||
} else {
|
||||
newStr[j++] = compStr.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Set id
|
||||
comp.id = new String(newStr, 0, j);
|
||||
|
||||
// Set kind
|
||||
if (kindSep < 0) {
|
||||
comp.kind = ""; // no kind separator
|
||||
} else {
|
||||
// unescape kind
|
||||
j = 0;
|
||||
escaped = false;
|
||||
for (int i = kindSep+1; i < len; i++) {
|
||||
if (escaped) {
|
||||
newStr[j++] = compStr.charAt(i);
|
||||
escaped = false;
|
||||
} else if (compStr.charAt(i) == escapeChar) {
|
||||
if (i + 1 >= len) {
|
||||
throw new InvalidNameException(compStr +
|
||||
": unescaped \\ at end of component");
|
||||
} else if (isMeta(compStr.charAt(i+1))) {
|
||||
escaped = true;
|
||||
} else {
|
||||
throw new InvalidNameException(compStr +
|
||||
": invalid character being escaped");
|
||||
}
|
||||
} else {
|
||||
newStr[j++] = compStr.charAt(i);
|
||||
}
|
||||
}
|
||||
comp.kind = new String(newStr, 0, j);
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
private static String stringifyComponent(NameComponent comp) {
|
||||
StringBuffer one = new StringBuffer(escape(comp.id));
|
||||
if (comp.kind != null && !comp.kind.equals("")) {
|
||||
one.append(kindSeparator + escape(comp.kind));
|
||||
}
|
||||
if (one.length() == 0) {
|
||||
return ""+kindSeparator; // if neither id nor kind specified
|
||||
} else {
|
||||
return one.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with '.', '\', '/' escaped. Used when
|
||||
* stringifying the name into its INS stringified form.
|
||||
*/
|
||||
private static String escape(String str) {
|
||||
if (str.indexOf(kindSeparator) < 0 &&
|
||||
str.indexOf(compSeparator) < 0 &&
|
||||
str.indexOf(escapeChar) < 0) {
|
||||
return str; // no meta characters to escape
|
||||
} else {
|
||||
int len = str.length();
|
||||
int j = 0;
|
||||
char[] newStr = new char[len+len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (isMeta(str.charAt(i))) {
|
||||
newStr[j++] = escapeChar; // escape meta character
|
||||
}
|
||||
newStr[j++] = str.charAt(i);
|
||||
}
|
||||
return new String(newStr, 0, j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In INS, there are three meta characters: '.', '/' and '\'.
|
||||
*/
|
||||
private static boolean isMeta(char ch) {
|
||||
switch (ch) {
|
||||
case kindSeparator:
|
||||
case compSeparator:
|
||||
case escapeChar:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of CompoundName that bypasses the parsing
|
||||
* and stringifying code of the default CompoundName.
|
||||
*/
|
||||
static final class CNCompoundName extends CompoundName {
|
||||
CNCompoundName(Enumeration<String> enum_) {
|
||||
super(enum_, CNNameParser.mySyntax);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new CNCompoundName(getAll());
|
||||
}
|
||||
|
||||
public Name getPrefix(int posn) {
|
||||
Enumeration<String> comps = super.getPrefix(posn).getAll();
|
||||
return new CNCompoundName(comps);
|
||||
}
|
||||
|
||||
public Name getSuffix(int posn) {
|
||||
Enumeration<String> comps = super.getSuffix(posn).getAll();
|
||||
return new CNCompoundName(comps);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
try {
|
||||
// Convert Name to NameComponent[] then stringify
|
||||
return cosNameToInsString(nameToCosName(this));
|
||||
} catch (InvalidNameException e) {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -6599252802678482317L;
|
||||
}
|
||||
|
||||
// for testing only
|
||||
/*
|
||||
private static void print(String input) {
|
||||
try {
|
||||
System.out.println("\n >>>>>> input: " + input);
|
||||
|
||||
System.out.println("--Compound Name: ");
|
||||
NameParser parser = new CNNameParser();
|
||||
Name name = parser.parse(input);
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
System.out.println("\t" + i + ": " + name.get(i));
|
||||
NameComponent cp = parseComponent(name.get(i));
|
||||
System.out.println("\t\t" + "id: " + cp.id + ";kind: " + cp.kind);
|
||||
}
|
||||
System.out.println("\t" + name.toString());
|
||||
|
||||
System.out.println("--Composite Name: ");
|
||||
Name composite = new CompositeName(input);
|
||||
for (int i = 0; i < composite.size(); i++) {
|
||||
System.out.println("\t" + i+": " + composite.get(i));
|
||||
}
|
||||
System.out.println("\t" + composite.toString());
|
||||
|
||||
System.out.println("--Composite To NameComponent");
|
||||
NameComponent[] names = nameToCosName(composite);
|
||||
for (int i = 0; i < composite.size(); i++) {
|
||||
System.out.println("\t" + i+": id: " + names[i].id + "; kind: " + names[i].kind);
|
||||
}
|
||||
System.out.println("\t" + cosNameToInsString(names));
|
||||
} catch (NamingException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkName(Name name, String[] comps) throws Exception {
|
||||
if (name.size() != comps.length) {
|
||||
throw new Exception(
|
||||
"test failed; incorrect component count in " + name + "; " +
|
||||
"expecting " + comps.length + " got " + name.size());
|
||||
}
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
if (!comps[i].equals(name.get(i))) {
|
||||
throw new Exception (
|
||||
"test failed; invalid component in " + name + "; " +
|
||||
"expecting '" + comps[i] + "' got '" + name.get(i) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkCompound(NameParser parser,
|
||||
String input, String[] comps) throws Exception {
|
||||
checkName(parser.parse(input), comps);
|
||||
}
|
||||
|
||||
private static void checkComposite(String input, String[] comps)
|
||||
throws Exception {
|
||||
checkName(new CompositeName(input), comps);
|
||||
}
|
||||
|
||||
private static String[] compounds = {
|
||||
"a/b/c",
|
||||
"a.b/c.d",
|
||||
"a",
|
||||
".",
|
||||
"a.",
|
||||
"c.d",
|
||||
".e",
|
||||
"a/x\\/y\\/z/b",
|
||||
"a\\.b.c\\.d/e.f",
|
||||
"a/b\\\\/c",
|
||||
"x\\\\.y",
|
||||
"x\\.y",
|
||||
"x.\\\\y",
|
||||
"x.y\\\\",
|
||||
"\\\\x.y",
|
||||
"a.b\\.c/d"
|
||||
};
|
||||
private static String[][] compoundComps = {
|
||||
{"a", "b", "c"},
|
||||
{"a.b", "c.d"},
|
||||
{"a"},
|
||||
{"."},
|
||||
{"a"},
|
||||
{"c.d"},
|
||||
{".e"},
|
||||
{"a", "x\\/y\\/z", "b"},
|
||||
{"a\\.b.c\\.d", "e.f"},
|
||||
{"a", "b\\\\", "c"},
|
||||
{"x\\\\.y"},
|
||||
{"x\\.y"},
|
||||
{"x.\\\\y"},
|
||||
{"x.y\\\\"},
|
||||
{"\\\\x.y"},
|
||||
{"a.b\\.c", "d"},
|
||||
};
|
||||
|
||||
private static String[] composites = {
|
||||
"a/b/c",
|
||||
"a.b/c.d",
|
||||
"a",
|
||||
".",
|
||||
"a.",
|
||||
"c.d",
|
||||
".e",
|
||||
"a/x\\\\\\/y\\\\\\/z/b",
|
||||
"a\\\\.b.c\\\\.d/e.f",
|
||||
"a/b\\\\\\\\/c",
|
||||
"x\\\\\\.y",
|
||||
"x\\\\.y",
|
||||
"x.\\\\\\\\y",
|
||||
"x.y\\\\\\\\",
|
||||
"\\\\\\\\x.y"
|
||||
};
|
||||
|
||||
private static String[][] compositeComps = {
|
||||
{"a", "b", "c"},
|
||||
{"a.b", "c.d"},
|
||||
{"a"},
|
||||
{"."},
|
||||
{"a."}, // unlike compound, kind sep is not consumed
|
||||
{"c.d"},
|
||||
{".e"},
|
||||
{"a", "x\\/y\\/z", "b"},
|
||||
{"a\\.b.c\\.d", "e.f"},
|
||||
{"a", "b\\\\", "c"},
|
||||
{"x\\\\.y"},
|
||||
{"x\\.y"},
|
||||
{"x.\\\\y"},
|
||||
{"x.y\\\\"},
|
||||
{"\\\\x.y"}
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length > 0) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
print(args[0]);
|
||||
}
|
||||
} else {
|
||||
print("x\\\\.y");
|
||||
print("x\\.y");
|
||||
print("x.\\\\y");
|
||||
print("x.y\\\\");
|
||||
print("\\\\x.y");
|
||||
}
|
||||
|
||||
NameParser parser = new com.sun.jndi.cosnaming.CNNameParser();
|
||||
for (int i = 0; i < compounds.length; i++) {
|
||||
checkCompound(parser, compounds[i], compoundComps[i]);
|
||||
}
|
||||
for (int i = 0; i < composites.length; i++) {
|
||||
checkComposite(composites[i], compositeComps[i]);
|
||||
}
|
||||
|
||||
System.out.println("hardwire");
|
||||
NameComponent[] foo = new NameComponent[1];
|
||||
foo[0] = new NameComponent("foo\\", "bar");
|
||||
|
||||
System.out.println(cosNameToInsString(foo));
|
||||
System.out.println(cosNameToName(foo));
|
||||
}
|
||||
*/
|
||||
}
|
||||
128
jdkSrc/jdk8/com/sun/jndi/cosnaming/CorbanameUrl.java
Normal file
128
jdkSrc/jdk8/com/sun/jndi/cosnaming/CorbanameUrl.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.cosnaming;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
|
||||
/**
|
||||
* Extract components of a "corbaname" URL.
|
||||
*
|
||||
* The format of an corbaname URL is defined in INS 99-12-03 as follows.
|
||||
*<p>
|
||||
* corbaname url = "corbaname:" <corbaloc_obj> ["#" <string_name>]
|
||||
* corbaloc_obj = <obj_addr_list> ["/" <key_string>]
|
||||
* obj_addr_list = as defined in a corbaloc URL
|
||||
* key_string = as defined in a corbaloc URL
|
||||
* string_name = stringified COS name | empty_string
|
||||
*<p>
|
||||
* Characters in <string_name> are escaped as follows.
|
||||
* US-ASCII alphanumeric characters are not escaped. Any characters outside
|
||||
* of this range are escaped except for the following:
|
||||
* ; / : ? @ & = + $ , - _ . ! ~ * ; ( )
|
||||
* Escaped characters is escaped by using a % followed by its 2 hexadecimal
|
||||
* numbers representing the octet.
|
||||
*<p>
|
||||
* The corbaname URL is parsed into two parts: a corbaloc URL and a COS name.
|
||||
* The corbaloc URL is constructed by concatenation "corbaloc:" with
|
||||
* <corbaloc_obj>.
|
||||
* The COS name is <string_name> with the escaped characters resolved.
|
||||
*<p>
|
||||
* A corbaname URL is resolved by:
|
||||
*<ol>
|
||||
*<li>Construct a corbaloc URL by concatenating "corbaloc:" and <corbaloc_obj>.
|
||||
*<li>Resolve the corbaloc URL to a NamingContext by using
|
||||
* nctx = ORB.string_to_object(corbalocUrl);
|
||||
*<li>Resolve <string_name> in the NamingContext.
|
||||
*</ol>
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
public final class CorbanameUrl {
|
||||
private String stringName;
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* Returns a possibly empty but non-null string that is the "string_name"
|
||||
* portion of the URL.
|
||||
*/
|
||||
public String getStringName() {
|
||||
return stringName;
|
||||
}
|
||||
|
||||
public Name getCosName() throws NamingException {
|
||||
return CNCtx.parser.parse(stringName);
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return "corbaloc:" + location;
|
||||
}
|
||||
|
||||
public CorbanameUrl(String url) throws MalformedURLException {
|
||||
|
||||
if (!url.startsWith("corbaname:")) {
|
||||
throw new MalformedURLException("Invalid corbaname URL: " + url);
|
||||
}
|
||||
|
||||
int addrStart = 10; // "corbaname:"
|
||||
|
||||
int addrEnd = url.indexOf('#', addrStart);
|
||||
if (addrEnd < 0) {
|
||||
addrEnd = url.length();
|
||||
stringName = "";
|
||||
} else {
|
||||
stringName = UrlUtil.decode(url.substring(addrEnd+1));
|
||||
}
|
||||
location = url.substring(addrStart, addrEnd);
|
||||
|
||||
int keyStart = location.indexOf("/");
|
||||
if (keyStart >= 0) {
|
||||
// Has key string
|
||||
if (keyStart == (location.length() -1)) {
|
||||
location += "NameService";
|
||||
}
|
||||
} else {
|
||||
location += "/NameService";
|
||||
}
|
||||
}
|
||||
/*
|
||||
// for testing only
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
CorbanameUrl url = new CorbanameUrl(args[0]);
|
||||
|
||||
System.out.println("location: " + url.getLocation());
|
||||
System.out.println("string name: " + url.getStringName());
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
247
jdkSrc/jdk8/com/sun/jndi/cosnaming/ExceptionMapper.java
Normal file
247
jdkSrc/jdk8/com/sun/jndi/cosnaming/ExceptionMapper.java
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.*;
|
||||
|
||||
import org.omg.CosNaming.*;
|
||||
import org.omg.CosNaming.NamingContextPackage.*;
|
||||
import org.omg.CORBA.*;
|
||||
|
||||
import com.sun.jndi.toolkit.corba.CorbaUtils;
|
||||
|
||||
/**
|
||||
* A convenience class to map the COS Naming exceptions to the JNDI exceptions.
|
||||
* @author Raj Krishnamurthy
|
||||
*/
|
||||
|
||||
public final class ExceptionMapper {
|
||||
private ExceptionMapper() {} // ensure no instance
|
||||
private static final boolean debug = false;
|
||||
|
||||
public static final NamingException mapException(Exception e,
|
||||
CNCtx ctx, NameComponent[] inputName) throws NamingException {
|
||||
if (e instanceof NamingException) {
|
||||
return (NamingException)e;
|
||||
}
|
||||
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException)e;
|
||||
}
|
||||
|
||||
NamingException ne;
|
||||
if (e instanceof NotFound) {
|
||||
if (ctx.federation) {
|
||||
return tryFed((NotFound)e, ctx, inputName);
|
||||
|
||||
} else {
|
||||
ne = new NameNotFoundException();
|
||||
}
|
||||
|
||||
} else if (e instanceof CannotProceed) {
|
||||
|
||||
ne = new CannotProceedException();
|
||||
NamingContext nc = ((CannotProceed) e).cxt;
|
||||
NameComponent[] rest = ((CannotProceed) e).rest_of_name;
|
||||
|
||||
// %%% We assume that rest returns *all* unprocessed components.
|
||||
// Don't' know if that is a good assumption, given
|
||||
// NotFound doesn't set rest as expected. -RL
|
||||
if (inputName != null && (inputName.length > rest.length)) {
|
||||
NameComponent[] resolvedName =
|
||||
new NameComponent[inputName.length - rest.length];
|
||||
System.arraycopy(inputName, 0, resolvedName, 0, resolvedName.length);
|
||||
// Wrap resolved NamingContext inside a CNCtx
|
||||
// Guess that its name (which is relative to ctx)
|
||||
// is the part of inputName minus rest_of_name
|
||||
ne.setResolvedObj(new CNCtx(ctx._orb, ctx.orbTracker, nc,
|
||||
ctx._env,
|
||||
ctx.makeFullName(resolvedName)));
|
||||
} else {
|
||||
ne.setResolvedObj(ctx);
|
||||
}
|
||||
|
||||
ne.setRemainingName(CNNameParser.cosNameToName(rest));
|
||||
|
||||
} else if (e instanceof InvalidName) {
|
||||
ne = new InvalidNameException();
|
||||
} else if (e instanceof AlreadyBound) {
|
||||
ne = new NameAlreadyBoundException();
|
||||
} else if (e instanceof NotEmpty) {
|
||||
ne = new ContextNotEmptyException();
|
||||
} else {
|
||||
ne = new NamingException("Unknown reasons");
|
||||
}
|
||||
|
||||
ne.setRootCause(e);
|
||||
return ne;
|
||||
}
|
||||
|
||||
private static final NamingException tryFed(NotFound e, CNCtx ctx,
|
||||
NameComponent[] inputName) throws NamingException {
|
||||
NameComponent[] rest = e.rest_of_name;
|
||||
|
||||
if (debug) {
|
||||
System.out.println(e.why.value());
|
||||
System.out.println(rest.length);
|
||||
}
|
||||
|
||||
// %%% Using 1.2 & 1.3 Sun's tnameserv, 'rest' contains only the first
|
||||
// component that failed, not *rest* as advertized. This is useless
|
||||
// because what if you have something like aa/aa/aa/aa/aa.
|
||||
// If one of those is not found, you get "aa" as 'rest'.
|
||||
if (rest.length == 1 && inputName != null) {
|
||||
// Check that we're not talking to 1.2/1.3 Sun tnameserv
|
||||
NameComponent lastIn = inputName[inputName.length-1];
|
||||
if (rest[0].id.equals(lastIn.id) &&
|
||||
rest[0].kind != null &&
|
||||
rest[0].kind.equals(lastIn.kind)) {
|
||||
// Might be legit
|
||||
;
|
||||
} else {
|
||||
// Due to 1.2/1.3 bug that always returns single-item 'rest'
|
||||
NamingException ne = new NameNotFoundException();
|
||||
ne.setRemainingName(CNNameParser.cosNameToName(rest));
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
// Fixed in 1.4; perform calculations based on correct (1.4) behavior
|
||||
|
||||
// Calculate the components of the name that has been resolved
|
||||
NameComponent[] resolvedName = null;
|
||||
int len = 0;
|
||||
if (inputName != null && (inputName.length >= rest.length)) {
|
||||
|
||||
if (e.why == NotFoundReason.not_context) {
|
||||
// First component of rest is found but not a context; keep it
|
||||
// as part of resolved name
|
||||
len = inputName.length - (rest.length - 1);
|
||||
|
||||
// Remove resolved component from rest
|
||||
if (rest.length == 1) {
|
||||
// No more remaining
|
||||
rest = null;
|
||||
} else {
|
||||
NameComponent[] tmp = new NameComponent[rest.length-1];
|
||||
System.arraycopy(rest, 1, tmp, 0, tmp.length);
|
||||
rest = tmp;
|
||||
}
|
||||
} else {
|
||||
len = inputName.length - rest.length;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
resolvedName = new NameComponent[len];
|
||||
System.arraycopy(inputName, 0, resolvedName, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
// Create CPE and set common fields
|
||||
CannotProceedException cpe = new CannotProceedException();
|
||||
cpe.setRootCause(e);
|
||||
if (rest != null && rest.length > 0) {
|
||||
cpe.setRemainingName(CNNameParser.cosNameToName(rest));
|
||||
}
|
||||
cpe.setEnvironment(ctx._env);
|
||||
|
||||
if (debug) {
|
||||
System.out.println("rest of name: " + cpe.getRemainingName());
|
||||
}
|
||||
|
||||
// Lookup resolved name to get resolved object
|
||||
final java.lang.Object resolvedObj =
|
||||
(resolvedName != null) ? ctx.callResolve(resolvedName) : ctx;
|
||||
|
||||
if (resolvedObj instanceof javax.naming.Context) {
|
||||
// obj is a context and child is not found
|
||||
// try getting its nns dynamically by constructing
|
||||
// a Reference containing obj.
|
||||
RefAddr addr = new RefAddr("nns") {
|
||||
public java.lang.Object getContent() {
|
||||
return resolvedObj;
|
||||
}
|
||||
private static final long serialVersionUID =
|
||||
669984699392133792L;
|
||||
};
|
||||
Reference ref = new Reference("java.lang.Object", addr);
|
||||
|
||||
// Resolved name has trailing slash to indicate nns
|
||||
CompositeName cname = new CompositeName();
|
||||
cname.add(""); // add trailing slash
|
||||
|
||||
cpe.setResolvedObj(ref);
|
||||
cpe.setAltName(cname);
|
||||
cpe.setAltNameCtx((javax.naming.Context)resolvedObj);
|
||||
|
||||
return cpe;
|
||||
} else {
|
||||
// Not a context, use object factory to transform object.
|
||||
|
||||
Name cname = CNNameParser.cosNameToName(resolvedName);
|
||||
java.lang.Object resolvedObj2 = null;
|
||||
try {
|
||||
// Check whether object factory codebase is trusted
|
||||
if (CorbaUtils.isObjectFactoryTrusted(resolvedObj)) {
|
||||
resolvedObj2 = NamingManager.getObjectInstance(resolvedObj,
|
||||
cname, ctx, ctx._env);
|
||||
}
|
||||
} catch (NamingException ge) {
|
||||
throw ge;
|
||||
} catch (Exception ge) {
|
||||
NamingException ne = new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(ge);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// If a context, continue operation with context
|
||||
if (resolvedObj2 instanceof javax.naming.Context) {
|
||||
cpe.setResolvedObj(resolvedObj2);
|
||||
} else {
|
||||
// Add trailing slash
|
||||
cname.add("");
|
||||
cpe.setAltName(cname);
|
||||
|
||||
// Create nns reference
|
||||
final java.lang.Object rf2 = resolvedObj2;
|
||||
RefAddr addr = new RefAddr("nns") {
|
||||
public java.lang.Object getContent() {
|
||||
return rf2;
|
||||
}
|
||||
private static final long serialVersionUID =
|
||||
-785132553978269772L;
|
||||
};
|
||||
Reference ref = new Reference("java.lang.Object", addr);
|
||||
cpe.setResolvedObj(ref);
|
||||
cpe.setAltNameCtx(ctx);
|
||||
}
|
||||
return cpe;
|
||||
}
|
||||
}
|
||||
}
|
||||
223
jdkSrc/jdk8/com/sun/jndi/cosnaming/IiopUrl.java
Normal file
223
jdkSrc/jdk8/com/sun/jndi/cosnaming/IiopUrl.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Vector;
|
||||
import java.util.StringTokenizer;
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
|
||||
/**
|
||||
* Extract components of an "iiop" or "iiopname" URL.
|
||||
*
|
||||
* The format of an iiopname URL is defined in INS 98-10-11 as follows:
|
||||
*
|
||||
* iiopname url = "iiopname://" [addr_list]["/" string_name]
|
||||
* addr_list = [address ","]* address
|
||||
* address = [version host [":" port]]
|
||||
* host = DNS style host name | IP address
|
||||
* version = major "." minor "@" | empty_string
|
||||
* port = number
|
||||
* major = number
|
||||
* minor = number
|
||||
* string_name = stringified name | empty_string
|
||||
*
|
||||
* The default port is 9999. The default version is "1.0"
|
||||
* US-ASCII alphanumeric characters are not escaped. Any characters outside
|
||||
* of this range are escaped except for the following:
|
||||
* ; / : ? : @ & = + $ , - _ . ! ~ * ' ( )
|
||||
* Escaped characters is escaped by using a % followed by its 2 hexadecimal
|
||||
* numbers representing the octet.
|
||||
*
|
||||
* For backward compatibility, the "iiop" URL as defined in INS 97-6-6
|
||||
* is also supported:
|
||||
*
|
||||
* iiop url = "iiop://" [host [":" port]] ["/" string_name]
|
||||
* The default port is 900.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
public final class IiopUrl {
|
||||
static final private int DEFAULT_IIOPNAME_PORT = 9999;
|
||||
static final private int DEFAULT_IIOP_PORT = 900;
|
||||
static final private String DEFAULT_HOST = "localhost";
|
||||
private Vector<Address> addresses;
|
||||
private String stringName;
|
||||
|
||||
public static class Address {
|
||||
public int port = -1;
|
||||
public int major, minor;
|
||||
public String host;
|
||||
|
||||
public Address(String hostPortVers, boolean oldFormat)
|
||||
throws MalformedURLException {
|
||||
// [version host [":" port]]
|
||||
int start;
|
||||
|
||||
// Parse version
|
||||
int at;
|
||||
if (oldFormat || (at = hostPortVers.indexOf('@')) < 0) {
|
||||
major = 1;
|
||||
minor = 0;
|
||||
start = 0; // start at the beginning
|
||||
} else {
|
||||
int dot = hostPortVers.indexOf('.');
|
||||
if (dot < 0) {
|
||||
throw new MalformedURLException(
|
||||
"invalid version: " + hostPortVers);
|
||||
}
|
||||
try {
|
||||
major = Integer.parseInt(hostPortVers.substring(0, dot));
|
||||
minor = Integer.parseInt(hostPortVers.substring(dot+1, at));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new MalformedURLException(
|
||||
"Nonnumeric version: " + hostPortVers);
|
||||
}
|
||||
start = at + 1; // skip '@' sign
|
||||
}
|
||||
|
||||
// Parse host and port
|
||||
int slash = hostPortVers.indexOf('/', start);
|
||||
if (slash < 0) {
|
||||
slash = hostPortVers.length();
|
||||
}
|
||||
if (hostPortVers.startsWith("[", start)) { // at IPv6 literal
|
||||
int brac = hostPortVers.indexOf(']', start + 1);
|
||||
if (brac < 0 || brac > slash) {
|
||||
throw new IllegalArgumentException(
|
||||
"IiopURL: name is an Invalid URL: " + hostPortVers);
|
||||
}
|
||||
|
||||
// include brackets
|
||||
host = hostPortVers.substring(start, brac + 1);
|
||||
start = brac + 1;
|
||||
} else { // at hostname or IPv4
|
||||
int colon = hostPortVers.indexOf(':', start);
|
||||
int hostEnd = (colon < 0 || colon > slash)
|
||||
? slash
|
||||
: colon;
|
||||
if (start < hostEnd) {
|
||||
host = hostPortVers.substring(start, hostEnd);
|
||||
}
|
||||
start = hostEnd; // skip past host
|
||||
}
|
||||
if ((start + 1 < slash)) {
|
||||
if ( hostPortVers.startsWith(":", start)) { // parse port
|
||||
start++; // skip past ":"
|
||||
port = Integer.parseInt(hostPortVers.
|
||||
substring(start, slash));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"IiopURL: name is an Invalid URL: " + hostPortVers);
|
||||
}
|
||||
}
|
||||
start = slash;
|
||||
if ("".equals(host) || host == null) {
|
||||
host = DEFAULT_HOST ;
|
||||
}
|
||||
if (port == -1) {
|
||||
port = (oldFormat ? DEFAULT_IIOP_PORT :
|
||||
DEFAULT_IIOPNAME_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a possibly empty but non-null string that is the "string_name"
|
||||
* portion of the URL.
|
||||
*/
|
||||
public String getStringName() {
|
||||
return stringName;
|
||||
}
|
||||
|
||||
public Name getCosName() throws NamingException {
|
||||
return CNCtx.parser.parse(stringName);
|
||||
}
|
||||
|
||||
public IiopUrl(String url) throws MalformedURLException {
|
||||
int addrStart;
|
||||
boolean oldFormat;
|
||||
|
||||
if (url.startsWith("iiopname://")) {
|
||||
oldFormat = false;
|
||||
addrStart = 11;
|
||||
} else if (url.startsWith("iiop://")) {
|
||||
oldFormat = true;
|
||||
addrStart = 7;
|
||||
} else {
|
||||
throw new MalformedURLException("Invalid iiop/iiopname URL: " + url);
|
||||
}
|
||||
int addrEnd = url.indexOf('/', addrStart);
|
||||
if (addrEnd < 0) {
|
||||
addrEnd = url.length();
|
||||
stringName = "";
|
||||
} else {
|
||||
stringName = UrlUtil.decode(url.substring(addrEnd+1));
|
||||
}
|
||||
addresses = new Vector<>(3);
|
||||
if (oldFormat) {
|
||||
// Only one host:port part, not multiple
|
||||
addresses.addElement(
|
||||
new Address(url.substring(addrStart, addrEnd), oldFormat));
|
||||
} else {
|
||||
StringTokenizer tokens =
|
||||
new StringTokenizer(url.substring(addrStart, addrEnd), ",");
|
||||
while (tokens.hasMoreTokens()) {
|
||||
addresses.addElement(new Address(tokens.nextToken(), oldFormat));
|
||||
}
|
||||
if (addresses.size() == 0) {
|
||||
addresses.addElement(new Address("", oldFormat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for testing only
|
||||
/*public static void main(String[] args) {
|
||||
try {
|
||||
IiopUrl url = new IiopUrl(args[0]);
|
||||
Vector addrs = url.getAddresses();
|
||||
String name = url.getStringName();
|
||||
|
||||
for (int i = 0; i < addrs.size(); i++) {
|
||||
Address addr = (Address)addrs.elementAt(i);
|
||||
System.out.println("host: " + addr.host);
|
||||
System.out.println("port: " + addr.port);
|
||||
System.out.println("version: " + addr.major + " " + addr.minor);
|
||||
}
|
||||
System.out.println("name: " + name);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} */
|
||||
}
|
||||
70
jdkSrc/jdk8/com/sun/jndi/cosnaming/OrbReuseTracker.java
Normal file
70
jdkSrc/jdk8/com/sun/jndi/cosnaming/OrbReuseTracker.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.cosnaming;
|
||||
|
||||
import org.omg.CORBA.ORB;
|
||||
|
||||
/**
|
||||
* This class keeps track of references to the shared ORB object
|
||||
* and destroys it when no more references are made to the ORB
|
||||
* object. This object is created for each ORB object that CNCtx
|
||||
* creates.
|
||||
*/
|
||||
class OrbReuseTracker {
|
||||
|
||||
int referenceCnt;
|
||||
ORB orb;
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
OrbReuseTracker(ORB orb) {
|
||||
this.orb = orb;
|
||||
referenceCnt++;
|
||||
if (debug) {
|
||||
System.out.println("New OrbReuseTracker created");
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void incRefCount() {
|
||||
referenceCnt++;
|
||||
if (debug) {
|
||||
System.out.println("Increment orb ref count to:" + referenceCnt);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void decRefCount() {
|
||||
referenceCnt--;
|
||||
if (debug) {
|
||||
System.out.println("Decrement orb ref count to:" + referenceCnt);
|
||||
}
|
||||
if ((referenceCnt == 0)) {
|
||||
if (debug) {
|
||||
System.out.println("Destroying the ORB");
|
||||
}
|
||||
orb.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
88
jdkSrc/jdk8/com/sun/jndi/cosnaming/RemoteToCorba.java
Normal file
88
jdkSrc/jdk8/com/sun/jndi/cosnaming/RemoteToCorba.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.cosnaming;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.spi.StateFactory;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.omg.CORBA.ORB;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.ExportException;
|
||||
|
||||
import com.sun.jndi.toolkit.corba.CorbaUtils; // for RMI-IIOP
|
||||
|
||||
/**
|
||||
* StateFactory that turns java.rmi.Remote objects to org.omg.CORBA.Object.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
public class RemoteToCorba implements StateFactory {
|
||||
public RemoteToCorba() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CORBA object for a Remote object.
|
||||
* If input is not a Remote object, or if Remote object uses JRMP, return null.
|
||||
* If the RMI-IIOP library is not available, throw ConfigurationException.
|
||||
*
|
||||
* @param orig The object to turn into a CORBA object. If not Remote,
|
||||
* or if is a JRMP stub or impl, return null.
|
||||
* @param name Ignored
|
||||
* @param ctx The non-null CNCtx whose ORB to use.
|
||||
* @param env Ignored
|
||||
* @return The CORBA object for <tt>orig</tt> or null.
|
||||
* @exception ConfigurationException If the CORBA object cannot be obtained
|
||||
* due to configuration problems, for instance, if RMI-IIOP not available.
|
||||
* @exception NamingException If some other problem prevented a CORBA
|
||||
* object from being obtained from the Remote object.
|
||||
*/
|
||||
public Object getStateToBind(Object orig, Name name, Context ctx,
|
||||
Hashtable<?,?> env) throws NamingException {
|
||||
if (orig instanceof org.omg.CORBA.Object) {
|
||||
// Already a CORBA object, just use it
|
||||
return null;
|
||||
}
|
||||
|
||||
if (orig instanceof Remote) {
|
||||
// Turn remote object into org.omg.CORBA.Object
|
||||
try {
|
||||
// Returns null if JRMP; let next factory try
|
||||
// CNCtx will eventually throw IllegalArgumentException if
|
||||
// no CORBA object gotten
|
||||
return
|
||||
CorbaUtils.remoteToCorba((Remote)orig, ((CNCtx)ctx)._orb);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// RMI-IIOP library not available
|
||||
throw new ConfigurationException(
|
||||
"javax.rmi packages not available");
|
||||
}
|
||||
}
|
||||
return null; // pass and let next state factory try
|
||||
}
|
||||
}
|
||||
295
jdkSrc/jdk8/com/sun/jndi/dns/DNSDatagramSocketFactory.java
Normal file
295
jdkSrc/jdk8/com/sun/jndi/dns/DNSDatagramSocketFactory.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.dns;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.SocketException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
class DNSDatagramSocketFactory {
|
||||
static final int DEVIATION = 3;
|
||||
static final int THRESHOLD = 6;
|
||||
static final int BIT_DEVIATION = 2;
|
||||
static final int HISTORY = 32;
|
||||
static final int MAX_RANDOM_TRIES = 5;
|
||||
/**
|
||||
* The dynamic allocation port range (aka ephemeral ports), as configured
|
||||
* on the system. Use nested class for lazy evaluation.
|
||||
*/
|
||||
static final class EphemeralPortRange {
|
||||
private EphemeralPortRange() {}
|
||||
static final int LOWER = sun.net.PortConfig.getLower();
|
||||
static final int UPPER = sun.net.PortConfig.getUpper();
|
||||
static final int RANGE = UPPER - LOWER + 1;
|
||||
}
|
||||
|
||||
private static int findFirstFreePort() {
|
||||
PrivilegedExceptionAction<DatagramSocket> action = () -> new DatagramSocket(0);
|
||||
int port;
|
||||
try {
|
||||
@SuppressWarnings({"deprecated", "removal"})
|
||||
DatagramSocket ds = AccessController.doPrivileged(action);
|
||||
try (DatagramSocket ds1 = ds) {
|
||||
port = ds1.getLocalPort();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
port = 0;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
// Records a subset of max {@code capacity} previously used ports
|
||||
static final class PortHistory {
|
||||
final int capacity;
|
||||
final int[] ports;
|
||||
final Random random;
|
||||
int index;
|
||||
PortHistory(int capacity, Random random) {
|
||||
this.random = random;
|
||||
this.capacity = capacity;
|
||||
this.ports = new int[capacity];
|
||||
}
|
||||
// returns true if the history contains the specified port.
|
||||
public boolean contains(int port) {
|
||||
int p = 0;
|
||||
for (int i=0; i<capacity; i++) {
|
||||
if ((p = ports[i]) == 0 || p == port) break;
|
||||
}
|
||||
return p == port;
|
||||
}
|
||||
// Adds the port to the history - doesn't check whether the port
|
||||
// is already present. Always adds the port and always return true.
|
||||
public boolean add(int port) {
|
||||
if (ports[index] != 0) { // at max capacity
|
||||
// remove one port at random and store the new port there
|
||||
// don't remove the last port
|
||||
int remove = random.nextInt(capacity);
|
||||
if ((remove +1) % capacity == index) remove = index;
|
||||
ports[index = remove] = port;
|
||||
} else { // there's a free slot
|
||||
ports[index] = port;
|
||||
}
|
||||
if (++index == capacity) index = 0;
|
||||
return true;
|
||||
}
|
||||
// Adds the port to the history if not already present.
|
||||
// Return true if the port was added, false if the port was already
|
||||
// present.
|
||||
public boolean offer(int port) {
|
||||
if (contains(port)) return false;
|
||||
else return add(port);
|
||||
}
|
||||
}
|
||||
|
||||
int lastport = findFirstFreePort();
|
||||
int lastSystemAllocated = lastport;
|
||||
int suitablePortCount;
|
||||
int unsuitablePortCount;
|
||||
final ProtocolFamily family; // null (default) means dual stack
|
||||
final int thresholdCount; // decision point
|
||||
final int deviation;
|
||||
final Random random;
|
||||
final PortHistory history;
|
||||
|
||||
DNSDatagramSocketFactory() {
|
||||
this(new Random());
|
||||
}
|
||||
|
||||
DNSDatagramSocketFactory(Random random) {
|
||||
this(Objects.requireNonNull(random), null, DEVIATION, THRESHOLD);
|
||||
}
|
||||
DNSDatagramSocketFactory(Random random,
|
||||
ProtocolFamily family,
|
||||
int deviation,
|
||||
int threshold) {
|
||||
this.random = Objects.requireNonNull(random);
|
||||
this.history = new PortHistory(HISTORY, random);
|
||||
this.family = family;
|
||||
this.deviation = Math.max(1, deviation);
|
||||
this.thresholdCount = Math.max(2, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a datagram socket listening to the wildcard address on a
|
||||
* random port. If the underlying OS supports UDP port randomization
|
||||
* out of the box (if binding a socket to port 0 binds it to a random
|
||||
* port) then the underlying OS implementation is used. Otherwise, this
|
||||
* method will allocate and bind a socket on a randomly selected ephemeral
|
||||
* port in the dynamic range.
|
||||
* @return A new DatagramSocket bound to a random port.
|
||||
* @throws SocketException if the socket cannot be created.
|
||||
*/
|
||||
public synchronized DatagramSocket open() throws SocketException {
|
||||
int lastseen = lastport;
|
||||
DatagramSocket s;
|
||||
|
||||
boolean thresholdCrossed = unsuitablePortCount > thresholdCount;
|
||||
if (thresholdCrossed) {
|
||||
// Underlying stack does not support random UDP port out of the box.
|
||||
// Use our own algorithm to allocate a random UDP port
|
||||
s = openRandom();
|
||||
if (s != null) return s;
|
||||
|
||||
// couldn't allocate a random port: reset all counters and fall
|
||||
// through.
|
||||
unsuitablePortCount = 0; suitablePortCount = 0; lastseen = 0;
|
||||
}
|
||||
|
||||
// Allocate an ephemeral port (port 0)
|
||||
s = openDefault();
|
||||
lastport = s.getLocalPort();
|
||||
if (lastseen == 0) {
|
||||
lastSystemAllocated = lastport;
|
||||
history.offer(lastport);
|
||||
return s;
|
||||
}
|
||||
|
||||
thresholdCrossed = suitablePortCount > thresholdCount;
|
||||
boolean farEnough = farEnough(lastseen);
|
||||
if (farEnough && lastSystemAllocated > 0) {
|
||||
farEnough = farEnough(lastSystemAllocated);
|
||||
}
|
||||
boolean recycled = history.contains(lastport);
|
||||
boolean suitable = (thresholdCrossed || farEnough && !recycled);
|
||||
if (suitable && !recycled) history.add(lastport);
|
||||
|
||||
if (suitable) {
|
||||
if (!thresholdCrossed) {
|
||||
suitablePortCount++;
|
||||
} else if (!farEnough || recycled) {
|
||||
unsuitablePortCount = 1;
|
||||
suitablePortCount = thresholdCount/2;
|
||||
}
|
||||
// Either the underlying stack supports random UDP port allocation,
|
||||
// or the new port is sufficiently distant from last port to make
|
||||
// it look like it is. Let's use it.
|
||||
lastSystemAllocated = lastport;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Undecided... the new port was too close. Let's allocate a random
|
||||
// port using our own algorithm
|
||||
assert !thresholdCrossed;
|
||||
DatagramSocket ss = openRandom();
|
||||
if (ss == null) return s;
|
||||
unsuitablePortCount++;
|
||||
s.close();
|
||||
return ss;
|
||||
}
|
||||
|
||||
private DatagramSocket openDefault() throws SocketException {
|
||||
if (family != null) {
|
||||
try {
|
||||
DatagramChannel c = DatagramChannel.open(family);
|
||||
try {
|
||||
DatagramSocket s = c.socket();
|
||||
s.bind(null);
|
||||
return s;
|
||||
} catch (Throwable x) {
|
||||
c.close();
|
||||
throw x;
|
||||
}
|
||||
} catch (SocketException x) {
|
||||
throw x;
|
||||
} catch (IOException x) {
|
||||
SocketException e = new SocketException(x.getMessage());
|
||||
e.initCause(x);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return new DatagramSocket();
|
||||
}
|
||||
|
||||
synchronized boolean isUsingNativePortRandomization() {
|
||||
return unsuitablePortCount <= thresholdCount
|
||||
&& suitablePortCount > thresholdCount;
|
||||
}
|
||||
|
||||
synchronized boolean isUsingJavaPortRandomization() {
|
||||
return unsuitablePortCount > thresholdCount ;
|
||||
}
|
||||
|
||||
synchronized boolean isUndecided() {
|
||||
return !isUsingJavaPortRandomization()
|
||||
&& !isUsingNativePortRandomization();
|
||||
}
|
||||
|
||||
private boolean farEnough(int port) {
|
||||
return Integer.bitCount(port ^ lastport) > BIT_DEVIATION
|
||||
&& Math.abs(port - lastport) > deviation;
|
||||
}
|
||||
|
||||
private DatagramSocket openRandom() {
|
||||
int maxtries = MAX_RANDOM_TRIES;
|
||||
while (maxtries-- > 0) {
|
||||
int port;
|
||||
boolean suitable;
|
||||
boolean recycled;
|
||||
int maxrandom = MAX_RANDOM_TRIES;
|
||||
do {
|
||||
port = EphemeralPortRange.LOWER
|
||||
+ random.nextInt(EphemeralPortRange.RANGE);
|
||||
recycled = history.contains(port);
|
||||
suitable = lastport == 0 || (farEnough(port) && !recycled);
|
||||
} while (maxrandom-- > 0 && !suitable);
|
||||
|
||||
// if no suitable port was found, try again
|
||||
// this means we might call random MAX_RANDOM_TRIES x MAX_RANDOM_TRIES
|
||||
// times - but that should be OK with MAX_RANDOM_TRIES = 5.
|
||||
if (!suitable) continue;
|
||||
|
||||
try {
|
||||
if (family != null) {
|
||||
DatagramChannel c = DatagramChannel.open(family);
|
||||
try {
|
||||
DatagramSocket s = c.socket();
|
||||
s.bind(new InetSocketAddress(port));
|
||||
lastport = s.getLocalPort();
|
||||
if (!recycled) history.add(port);
|
||||
return s;
|
||||
} catch (Throwable x) {
|
||||
c.close();
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
DatagramSocket s = new DatagramSocket(port);
|
||||
lastport = s.getLocalPort();
|
||||
if (!recycled) history.add(port);
|
||||
return s;
|
||||
} catch (IOException x) {
|
||||
// try again until maxtries == 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
742
jdkSrc/jdk8/com/sun/jndi/dns/DnsClient.java
Normal file
742
jdkSrc/jdk8/com/sun/jndi/dns/DnsClient.java
Normal file
@@ -0,0 +1,742 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2015, 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.dns;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.SecureRandom;
|
||||
import javax.naming.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
// Some of this code began life as part of sun.javaos.net.DnsClient
|
||||
// originally by sritchie@eng 1/96. It was first hacked up for JNDI
|
||||
// use by caveh@eng 6/97.
|
||||
|
||||
|
||||
/**
|
||||
* The DnsClient class performs DNS client operations in support of DnsContext.
|
||||
*
|
||||
*/
|
||||
|
||||
public class DnsClient {
|
||||
|
||||
// DNS packet header field offsets
|
||||
private static final int IDENT_OFFSET = 0;
|
||||
private static final int FLAGS_OFFSET = 2;
|
||||
private static final int NUMQ_OFFSET = 4;
|
||||
private static final int NUMANS_OFFSET = 6;
|
||||
private static final int NUMAUTH_OFFSET = 8;
|
||||
private static final int NUMADD_OFFSET = 10;
|
||||
private static final int DNS_HDR_SIZE = 12;
|
||||
|
||||
// DNS response codes
|
||||
private static final int NO_ERROR = 0;
|
||||
private static final int FORMAT_ERROR = 1;
|
||||
private static final int SERVER_FAILURE = 2;
|
||||
private static final int NAME_ERROR = 3;
|
||||
private static final int NOT_IMPL = 4;
|
||||
private static final int REFUSED = 5;
|
||||
|
||||
private static final String[] rcodeDescription = {
|
||||
"No error",
|
||||
"DNS format error",
|
||||
"DNS server failure",
|
||||
"DNS name not found",
|
||||
"DNS operation not supported",
|
||||
"DNS service refused"
|
||||
};
|
||||
|
||||
private static final int DEFAULT_PORT = 53;
|
||||
private static final int TRANSACTION_ID_BOUND = 0x10000;
|
||||
private static final SecureRandom random = JCAUtil.getSecureRandom();
|
||||
private InetAddress[] servers;
|
||||
private int[] serverPorts;
|
||||
private int timeout; // initial timeout on UDP queries in ms
|
||||
private int retries; // number of UDP retries
|
||||
|
||||
private final Object udpSocketLock = new Object();
|
||||
private static final DNSDatagramSocketFactory factory =
|
||||
new DNSDatagramSocketFactory(random);
|
||||
|
||||
// Requests sent
|
||||
private Map<Integer, ResourceRecord> reqs;
|
||||
|
||||
// Responses received
|
||||
private Map<Integer, byte[]> resps;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Each server is of the form "server[:port]". IPv6 literal host names
|
||||
* include delimiting brackets.
|
||||
* "timeout" is the initial timeout interval (in ms) for UDP queries,
|
||||
* and "retries" gives the number of retries per server.
|
||||
*/
|
||||
public DnsClient(String[] servers, int timeout, int retries)
|
||||
throws NamingException {
|
||||
this.timeout = timeout;
|
||||
this.retries = retries;
|
||||
this.servers = new InetAddress[servers.length];
|
||||
serverPorts = new int[servers.length];
|
||||
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
|
||||
// Is optional port given?
|
||||
int colon = servers[i].indexOf(':',
|
||||
servers[i].indexOf(']') + 1);
|
||||
|
||||
serverPorts[i] = (colon < 0)
|
||||
? DEFAULT_PORT
|
||||
: Integer.parseInt(servers[i].substring(colon + 1));
|
||||
String server = (colon < 0)
|
||||
? servers[i]
|
||||
: servers[i].substring(0, colon);
|
||||
try {
|
||||
this.servers[i] = InetAddress.getByName(server);
|
||||
} catch (java.net.UnknownHostException e) {
|
||||
NamingException ne = new ConfigurationException(
|
||||
"Unknown DNS server: " + server);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
reqs = Collections.synchronizedMap(
|
||||
new HashMap<Integer, ResourceRecord>());
|
||||
resps = Collections.synchronizedMap(new HashMap<Integer, byte[]>());
|
||||
}
|
||||
|
||||
DatagramSocket getDatagramSocket() throws NamingException {
|
||||
try {
|
||||
return factory.open();
|
||||
} catch (java.net.SocketException e) {
|
||||
NamingException ne = new ConfigurationException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
// A lock to access the request and response queues in tandem.
|
||||
private Object queuesLock = new Object();
|
||||
|
||||
public void close() {
|
||||
synchronized (queuesLock) {
|
||||
reqs.clear();
|
||||
resps.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If recursion is true, recursion is requested on the query.
|
||||
* If auth is true, only authoritative responses are accepted; other
|
||||
* responses throw NameNotFoundException.
|
||||
*/
|
||||
ResourceRecords query(DnsName fqdn, int qclass, int qtype,
|
||||
boolean recursion, boolean auth)
|
||||
throws NamingException {
|
||||
|
||||
int xid;
|
||||
Packet pkt;
|
||||
ResourceRecord collision;
|
||||
|
||||
do {
|
||||
// Generate a random transaction ID
|
||||
xid = random.nextInt(TRANSACTION_ID_BOUND);
|
||||
pkt = makeQueryPacket(fqdn, xid, qclass, qtype, recursion);
|
||||
|
||||
// enqueue the outstanding request
|
||||
collision = reqs.putIfAbsent(xid, new ResourceRecord(pkt.getData(),
|
||||
pkt.length(), Header.HEADER_SIZE, true, false));
|
||||
|
||||
} while (collision != null);
|
||||
|
||||
Exception caughtException = null;
|
||||
boolean[] doNotRetry = new boolean[servers.length];
|
||||
|
||||
try {
|
||||
//
|
||||
// The UDP retry strategy is to try the 1st server, and then
|
||||
// each server in order. If no answer, double the timeout
|
||||
// and try each server again.
|
||||
//
|
||||
for (int retry = 0; retry < retries; retry++) {
|
||||
|
||||
// Try each name server.
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
if (doNotRetry[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// send the request packet and wait for a response.
|
||||
try {
|
||||
if (debug) {
|
||||
dprint("SEND ID (" + (retry + 1) + "): " + xid);
|
||||
}
|
||||
|
||||
byte[] msg = null;
|
||||
msg = doUdpQuery(pkt, servers[i], serverPorts[i],
|
||||
retry, xid);
|
||||
//
|
||||
// If the matching response is not got within the
|
||||
// given timeout, check if the response was enqueued
|
||||
// by some other thread, if not proceed with the next
|
||||
// server or retry.
|
||||
//
|
||||
if (msg == null) {
|
||||
if (resps.size() > 0) {
|
||||
msg = lookupResponse(xid);
|
||||
}
|
||||
if (msg == null) { // try next server or retry
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Header hdr = new Header(msg, msg.length);
|
||||
|
||||
if (auth && !hdr.authoritative) {
|
||||
caughtException = new NameNotFoundException(
|
||||
"DNS response not authoritative");
|
||||
doNotRetry[i] = true;
|
||||
continue;
|
||||
}
|
||||
if (hdr.truncated) { // message is truncated -- try TCP
|
||||
|
||||
// Try each server, starting with the one that just
|
||||
// provided the truncated message.
|
||||
for (int j = 0; j < servers.length; j++) {
|
||||
int ij = (i + j) % servers.length;
|
||||
if (doNotRetry[ij]) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Tcp tcp =
|
||||
new Tcp(servers[ij], serverPorts[ij]);
|
||||
byte[] msg2;
|
||||
try {
|
||||
msg2 = doTcpQuery(tcp, pkt);
|
||||
} finally {
|
||||
tcp.close();
|
||||
}
|
||||
Header hdr2 = new Header(msg2, msg2.length);
|
||||
if (hdr2.query) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: expecting response");
|
||||
}
|
||||
checkResponseCode(hdr2);
|
||||
|
||||
if (!auth || hdr2.authoritative) {
|
||||
// Got a valid response
|
||||
hdr = hdr2;
|
||||
msg = msg2;
|
||||
break;
|
||||
} else {
|
||||
doNotRetry[ij] = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Try next server, or use UDP response
|
||||
}
|
||||
} // servers
|
||||
}
|
||||
return new ResourceRecords(msg, msg.length, hdr, false);
|
||||
|
||||
} catch (IOException e) {
|
||||
if (debug) {
|
||||
dprint("Caught IOException:" + e);
|
||||
}
|
||||
if (caughtException == null) {
|
||||
caughtException = e;
|
||||
}
|
||||
// Use reflection to allow pre-1.4 compilation.
|
||||
// This won't be needed much longer.
|
||||
if (e.getClass().getName().equals(
|
||||
"java.net.PortUnreachableException")) {
|
||||
doNotRetry[i] = true;
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// This is authoritative, so return immediately
|
||||
throw e;
|
||||
} catch (CommunicationException e) {
|
||||
if (caughtException == null) {
|
||||
caughtException = e;
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
if (caughtException == null) {
|
||||
caughtException = e;
|
||||
}
|
||||
doNotRetry[i] = true;
|
||||
}
|
||||
} // servers
|
||||
} // retries
|
||||
|
||||
} finally {
|
||||
reqs.remove(xid); // cleanup
|
||||
}
|
||||
|
||||
if (caughtException instanceof NamingException) {
|
||||
throw (NamingException) caughtException;
|
||||
}
|
||||
// A network timeout or other error occurred.
|
||||
NamingException ne = new CommunicationException("DNS error");
|
||||
ne.setRootCause(caughtException);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
ResourceRecords queryZone(DnsName zone, int qclass, boolean recursion)
|
||||
throws NamingException {
|
||||
|
||||
int xid = random.nextInt(TRANSACTION_ID_BOUND);
|
||||
|
||||
Packet pkt = makeQueryPacket(zone, xid, qclass,
|
||||
ResourceRecord.QTYPE_AXFR, recursion);
|
||||
Exception caughtException = null;
|
||||
|
||||
// Try each name server.
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
try {
|
||||
Tcp tcp = new Tcp(servers[i], serverPorts[i]);
|
||||
byte[] msg;
|
||||
try {
|
||||
msg = doTcpQuery(tcp, pkt);
|
||||
Header hdr = new Header(msg, msg.length);
|
||||
// Check only rcode as per
|
||||
// draft-ietf-dnsext-axfr-clarify-04
|
||||
checkResponseCode(hdr);
|
||||
ResourceRecords rrs =
|
||||
new ResourceRecords(msg, msg.length, hdr, true);
|
||||
if (rrs.getFirstAnsType() != ResourceRecord.TYPE_SOA) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: zone xfer doesn't begin with SOA");
|
||||
}
|
||||
|
||||
if (rrs.answer.size() == 1 ||
|
||||
rrs.getLastAnsType() != ResourceRecord.TYPE_SOA) {
|
||||
// The response is split into multiple DNS messages.
|
||||
do {
|
||||
msg = continueTcpQuery(tcp);
|
||||
if (msg == null) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: incomplete zone transfer");
|
||||
}
|
||||
hdr = new Header(msg, msg.length);
|
||||
checkResponseCode(hdr);
|
||||
rrs.add(msg, msg.length, hdr);
|
||||
} while (rrs.getLastAnsType() !=
|
||||
ResourceRecord.TYPE_SOA);
|
||||
}
|
||||
|
||||
// Delete the duplicate SOA record.
|
||||
rrs.answer.removeElementAt(rrs.answer.size() - 1);
|
||||
return rrs;
|
||||
|
||||
} finally {
|
||||
tcp.close();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
caughtException = e;
|
||||
} catch (NameNotFoundException e) {
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
caughtException = e;
|
||||
}
|
||||
}
|
||||
if (caughtException instanceof NamingException) {
|
||||
throw (NamingException) caughtException;
|
||||
}
|
||||
NamingException ne = new CommunicationException(
|
||||
"DNS error during zone transfer");
|
||||
ne.setRootCause(caughtException);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tries to retreive an UDP packet matching the given xid
|
||||
* received within the timeout.
|
||||
* If a packet with different xid is received, the received packet
|
||||
* is enqueued with the corresponding xid in 'resps'.
|
||||
*/
|
||||
private byte[] doUdpQuery(Packet pkt, InetAddress server,
|
||||
int port, int retry, int xid)
|
||||
throws IOException, NamingException {
|
||||
|
||||
int minTimeout = 50; // msec after which there are no retries.
|
||||
|
||||
synchronized (udpSocketLock) {
|
||||
try (DatagramSocket udpSocket = getDatagramSocket()) {
|
||||
DatagramPacket opkt = new DatagramPacket(
|
||||
pkt.getData(), pkt.length(), server, port);
|
||||
DatagramPacket ipkt = new DatagramPacket(new byte[8000], 8000);
|
||||
// Packets may only be sent to or received from this server address
|
||||
udpSocket.connect(server, port);
|
||||
int pktTimeout = (timeout * (1 << retry));
|
||||
try {
|
||||
udpSocket.send(opkt);
|
||||
|
||||
// timeout remaining after successive 'receive()'
|
||||
int timeoutLeft = pktTimeout;
|
||||
int cnt = 0;
|
||||
do {
|
||||
if (debug) {
|
||||
cnt++;
|
||||
dprint("Trying RECEIVE(" +
|
||||
cnt + ") retry(" + (retry + 1) +
|
||||
") for:" + xid + " sock-timeout:" +
|
||||
timeoutLeft + " ms.");
|
||||
}
|
||||
udpSocket.setSoTimeout(timeoutLeft);
|
||||
long start = System.currentTimeMillis();
|
||||
udpSocket.receive(ipkt);
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
byte[] data = ipkt.getData();
|
||||
if (isMatchResponse(data, xid)) {
|
||||
return data;
|
||||
}
|
||||
timeoutLeft = pktTimeout - ((int) (end - start));
|
||||
} while (timeoutLeft > minTimeout);
|
||||
|
||||
} finally {
|
||||
udpSocket.disconnect();
|
||||
}
|
||||
return null; // no matching packet received within the timeout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a TCP query, and returns the first DNS message in the response.
|
||||
*/
|
||||
private byte[] doTcpQuery(Tcp tcp, Packet pkt) throws IOException {
|
||||
|
||||
int len = pkt.length();
|
||||
// Send 2-byte message length, then send message.
|
||||
tcp.out.write(len >> 8);
|
||||
tcp.out.write(len);
|
||||
tcp.out.write(pkt.getData(), 0, len);
|
||||
tcp.out.flush();
|
||||
|
||||
byte[] msg = continueTcpQuery(tcp);
|
||||
if (msg == null) {
|
||||
throw new IOException("DNS error: no response");
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the next DNS message from the TCP socket, or null on EOF.
|
||||
*/
|
||||
private byte[] continueTcpQuery(Tcp tcp) throws IOException {
|
||||
|
||||
int lenHi = tcp.in.read(); // high-order byte of response length
|
||||
if (lenHi == -1) {
|
||||
return null; // EOF
|
||||
}
|
||||
int lenLo = tcp.in.read(); // low-order byte of response length
|
||||
if (lenLo == -1) {
|
||||
throw new IOException("Corrupted DNS response: bad length");
|
||||
}
|
||||
int len = (lenHi << 8) | lenLo;
|
||||
byte[] msg = new byte[len];
|
||||
int pos = 0; // next unfilled position in msg
|
||||
while (len > 0) {
|
||||
int n = tcp.in.read(msg, pos, len);
|
||||
if (n == -1) {
|
||||
throw new IOException(
|
||||
"Corrupted DNS response: too little data");
|
||||
}
|
||||
len -= n;
|
||||
pos += n;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private Packet makeQueryPacket(DnsName fqdn, int xid,
|
||||
int qclass, int qtype, boolean recursion) {
|
||||
int qnameLen = fqdn.getOctets();
|
||||
int pktLen = DNS_HDR_SIZE + qnameLen + 4;
|
||||
Packet pkt = new Packet(pktLen);
|
||||
|
||||
short flags = recursion ? Header.RD_BIT : 0;
|
||||
|
||||
pkt.putShort(xid, IDENT_OFFSET);
|
||||
pkt.putShort(flags, FLAGS_OFFSET);
|
||||
pkt.putShort(1, NUMQ_OFFSET);
|
||||
pkt.putShort(0, NUMANS_OFFSET);
|
||||
pkt.putInt(0, NUMAUTH_OFFSET);
|
||||
|
||||
makeQueryName(fqdn, pkt, DNS_HDR_SIZE);
|
||||
pkt.putShort(qtype, DNS_HDR_SIZE + qnameLen);
|
||||
pkt.putShort(qclass, DNS_HDR_SIZE + qnameLen + 2);
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
// Builds a query name in pkt according to the RFC spec.
|
||||
private void makeQueryName(DnsName fqdn, Packet pkt, int off) {
|
||||
|
||||
// Loop through labels, least-significant first.
|
||||
for (int i = fqdn.size() - 1; i >= 0; i--) {
|
||||
String label = fqdn.get(i);
|
||||
int len = label.length();
|
||||
|
||||
pkt.putByte(len, off++);
|
||||
for (int j = 0; j < len; j++) {
|
||||
pkt.putByte(label.charAt(j), off++);
|
||||
}
|
||||
}
|
||||
if (!fqdn.hasRootLabel()) {
|
||||
pkt.putByte(0, off);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private byte[] lookupResponse(Integer xid) throws NamingException {
|
||||
//
|
||||
// Check the queued responses: some other thread in between
|
||||
// received the response for this request.
|
||||
//
|
||||
if (debug) {
|
||||
dprint("LOOKUP for: " + xid +
|
||||
"\tResponse Q:" + resps);
|
||||
}
|
||||
byte[] pkt;
|
||||
if ((pkt = resps.get(xid)) != null) {
|
||||
checkResponseCode(new Header(pkt, pkt.length));
|
||||
synchronized (queuesLock) {
|
||||
resps.remove(xid);
|
||||
reqs.remove(xid);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
dprint("FOUND (" + Thread.currentThread() +
|
||||
") for:" + xid);
|
||||
}
|
||||
}
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the header of an incoming DNS response.
|
||||
* Returns true if it matches the given xid and throws a naming
|
||||
* exception, if appropriate, based on the response code.
|
||||
*
|
||||
* Also checks that the domain name, type and class in the response
|
||||
* match those in the original query.
|
||||
*/
|
||||
private boolean isMatchResponse(byte[] pkt, int xid)
|
||||
throws NamingException {
|
||||
|
||||
Header hdr = new Header(pkt, pkt.length);
|
||||
if (hdr.query) {
|
||||
throw new CommunicationException("DNS error: expecting response");
|
||||
}
|
||||
|
||||
if (!reqs.containsKey(xid)) { // already received, ignore the response
|
||||
return false;
|
||||
}
|
||||
|
||||
// common case- the request sent matches the subsequent response read
|
||||
if (hdr.xid == xid) {
|
||||
if (debug) {
|
||||
dprint("XID MATCH:" + xid);
|
||||
}
|
||||
checkResponseCode(hdr);
|
||||
if (!hdr.query && hdr.numQuestions == 1) {
|
||||
|
||||
ResourceRecord rr = new ResourceRecord(pkt, pkt.length,
|
||||
Header.HEADER_SIZE, true, false);
|
||||
|
||||
// Retrieve the original query
|
||||
ResourceRecord query = reqs.get(xid);
|
||||
int qtype = query.getType();
|
||||
int qclass = query.getRrclass();
|
||||
DnsName qname = query.getName();
|
||||
|
||||
// Check that the type/class/name in the query section of the
|
||||
// response match those in the original query
|
||||
if ((qtype == ResourceRecord.QTYPE_STAR ||
|
||||
qtype == rr.getType()) &&
|
||||
(qclass == ResourceRecord.QCLASS_STAR ||
|
||||
qclass == rr.getRrclass()) &&
|
||||
qname.equals(rr.getName())) {
|
||||
|
||||
if (debug) {
|
||||
dprint("MATCH NAME:" + qname + " QTYPE:" + qtype +
|
||||
" QCLASS:" + qclass);
|
||||
}
|
||||
|
||||
// Remove the response for the xid if received by some other
|
||||
// thread.
|
||||
synchronized (queuesLock) {
|
||||
resps.remove(xid);
|
||||
reqs.remove(xid);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if (debug) {
|
||||
dprint("NO-MATCH NAME:" + qname + " QTYPE:" + qtype +
|
||||
" QCLASS:" + qclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// xid mis-match: enqueue the response, it may belong to some other
|
||||
// thread that has not yet had a chance to read its response.
|
||||
// enqueue only the first response, responses for retries are ignored.
|
||||
//
|
||||
synchronized (queuesLock) {
|
||||
if (reqs.containsKey(hdr.xid)) { // enqueue only the first response
|
||||
resps.put(hdr.xid, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
dprint("NO-MATCH SEND ID:" +
|
||||
xid + " RECVD ID:" + hdr.xid +
|
||||
" Response Q:" + resps +
|
||||
" Reqs size:" + reqs.size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throws an exception if appropriate for the response code of a
|
||||
* given header.
|
||||
*/
|
||||
private void checkResponseCode(Header hdr) throws NamingException {
|
||||
|
||||
int rcode = hdr.rcode;
|
||||
if (rcode == NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
String msg = (rcode < rcodeDescription.length)
|
||||
? rcodeDescription[rcode]
|
||||
: "DNS error";
|
||||
msg += " [response code " + rcode + "]";
|
||||
|
||||
switch (rcode) {
|
||||
case SERVER_FAILURE:
|
||||
throw new ServiceUnavailableException(msg);
|
||||
case NAME_ERROR:
|
||||
throw new NameNotFoundException(msg);
|
||||
case NOT_IMPL:
|
||||
case REFUSED:
|
||||
throw new OperationNotSupportedException(msg);
|
||||
case FORMAT_ERROR:
|
||||
default:
|
||||
throw new NamingException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
private static void dprint(String mess) {
|
||||
if (debug) {
|
||||
System.err.println("DNS: " + mess);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Tcp {
|
||||
|
||||
private Socket sock;
|
||||
java.io.InputStream in;
|
||||
java.io.OutputStream out;
|
||||
|
||||
Tcp(InetAddress server, int port) throws IOException {
|
||||
sock = new Socket(server, port);
|
||||
sock.setTcpNoDelay(true);
|
||||
out = new java.io.BufferedOutputStream(sock.getOutputStream());
|
||||
in = new java.io.BufferedInputStream(sock.getInputStream());
|
||||
}
|
||||
|
||||
void close() throws IOException {
|
||||
sock.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* javaos emulation -cj
|
||||
*/
|
||||
class Packet {
|
||||
byte buf[];
|
||||
|
||||
Packet(int len) {
|
||||
buf = new byte[len];
|
||||
}
|
||||
|
||||
Packet(byte data[], int len) {
|
||||
buf = new byte[len];
|
||||
System.arraycopy(data, 0, buf, 0, len);
|
||||
}
|
||||
|
||||
void putInt(int x, int off) {
|
||||
buf[off + 0] = (byte)(x >> 24);
|
||||
buf[off + 1] = (byte)(x >> 16);
|
||||
buf[off + 2] = (byte)(x >> 8);
|
||||
buf[off + 3] = (byte)x;
|
||||
}
|
||||
|
||||
void putShort(int x, int off) {
|
||||
buf[off + 0] = (byte)(x >> 8);
|
||||
buf[off + 1] = (byte)x;
|
||||
}
|
||||
|
||||
void putByte(int x, int off) {
|
||||
buf[off] = (byte)x;
|
||||
}
|
||||
|
||||
void putBytes(byte src[], int src_offset, int dst_offset, int len) {
|
||||
System.arraycopy(src, src_offset, buf, dst_offset, len);
|
||||
}
|
||||
|
||||
int length() {
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
byte[] getData() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
1089
jdkSrc/jdk8/com/sun/jndi/dns/DnsContext.java
Normal file
1089
jdkSrc/jdk8/com/sun/jndi/dns/DnsContext.java
Normal file
File diff suppressed because it is too large
Load Diff
256
jdkSrc/jdk8/com/sun/jndi/dns/DnsContextFactory.java
Normal file
256
jdkSrc/jdk8/com/sun/jndi/dns/DnsContextFactory.java
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.spi.*;
|
||||
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
import sun.net.dns.ResolverConfiguration; // available since 1.4.1
|
||||
|
||||
|
||||
/**
|
||||
* A DnsContextFactory serves as the initial context factory for DNS.
|
||||
*
|
||||
* <p> When an initial context is being created, the environment
|
||||
* property "java.naming.provider.url" should contain a DNS pseudo-URL
|
||||
* (see DnsUrl) or a space-separated list of them. Multiple URLs must
|
||||
* all have the same domain value.
|
||||
* If the property is not set, the default "dns:" is used.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class DnsContextFactory implements InitialContextFactory {
|
||||
|
||||
private static final String DEFAULT_URL = "dns:";
|
||||
private static final int DEFAULT_PORT = 53;
|
||||
|
||||
|
||||
public Context getInitialContext(Hashtable<?,?> env) throws NamingException {
|
||||
if (env == null) {
|
||||
env = new Hashtable<>(5);
|
||||
}
|
||||
return urlToContext(getInitCtxUrl(env), env);
|
||||
}
|
||||
|
||||
public static DnsContext getContext(String domain,
|
||||
String[] servers, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
return new DnsContext(domain, servers, env);
|
||||
}
|
||||
|
||||
/*
|
||||
* "urls" are used to determine the servers, but any domain
|
||||
* components are overridden by "domain".
|
||||
*/
|
||||
public static DnsContext getContext(String domain,
|
||||
DnsUrl[] urls, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
String[] servers = serversForUrls(urls);
|
||||
DnsContext ctx = getContext(domain, servers, env);
|
||||
if (platformServersUsed(urls)) {
|
||||
ctx.setProviderUrl(constructProviderUrl(domain, servers));
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public for use by product test suite.
|
||||
*/
|
||||
public static boolean platformServersAvailable() {
|
||||
return !filterNameServers(
|
||||
ResolverConfiguration.open().nameservers(), true
|
||||
).isEmpty();
|
||||
}
|
||||
|
||||
private static Context urlToContext(String url, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
DnsUrl[] urls;
|
||||
try {
|
||||
urls = DnsUrl.fromList(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ConfigurationException(e.getMessage());
|
||||
}
|
||||
if (urls.length == 0) {
|
||||
throw new ConfigurationException(
|
||||
"Invalid DNS pseudo-URL(s): " + url);
|
||||
}
|
||||
String domain = urls[0].getDomain();
|
||||
|
||||
// If multiple urls, all must have the same domain.
|
||||
for (int i = 1; i < urls.length; i++) {
|
||||
if (!domain.equalsIgnoreCase(urls[i].getDomain())) {
|
||||
throw new ConfigurationException(
|
||||
"Conflicting domains: " + url);
|
||||
}
|
||||
}
|
||||
return getContext(domain, urls, env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns all the servers specified in a set of URLs.
|
||||
* If a URL has no host (or port), the servers configured on the
|
||||
* underlying platform are used if possible. If no configured
|
||||
* servers can be found, then fall back to the old behavior of
|
||||
* using "localhost".
|
||||
* There must be at least one URL.
|
||||
*/
|
||||
private static String[] serversForUrls(DnsUrl[] urls)
|
||||
throws NamingException {
|
||||
|
||||
if (urls.length == 0) {
|
||||
throw new ConfigurationException("DNS pseudo-URL required");
|
||||
}
|
||||
|
||||
List<String> servers = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
String server = urls[i].getHost();
|
||||
int port = urls[i].getPort();
|
||||
|
||||
if (server == null && port < 0) {
|
||||
// No server or port given, so look to underlying platform.
|
||||
// ResolverConfiguration does some limited caching, so the
|
||||
// following is reasonably efficient even if called rapid-fire.
|
||||
List<String> platformServers = filterNameServers(
|
||||
ResolverConfiguration.open().nameservers(), false);
|
||||
if (!platformServers.isEmpty()) {
|
||||
servers.addAll(platformServers);
|
||||
continue; // on to next URL (if any, which is unlikely)
|
||||
}
|
||||
}
|
||||
|
||||
if (server == null) {
|
||||
server = "localhost";
|
||||
}
|
||||
servers.add((port < 0)
|
||||
? server
|
||||
: server + ":" + port);
|
||||
}
|
||||
return servers.toArray(new String[servers.size()]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if serversForUrls(urls) would make use of servers
|
||||
* from the underlying platform.
|
||||
*/
|
||||
private static boolean platformServersUsed(DnsUrl[] urls) {
|
||||
if (!platformServersAvailable()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
if (urls[i].getHost() == null &&
|
||||
urls[i].getPort() < 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a value for the PROVIDER_URL property (space-separated URL
|
||||
* Strings) that reflects the given domain and servers.
|
||||
* Each server is of the form "server[:port]".
|
||||
* There must be at least one server.
|
||||
* IPv6 literal host names include delimiting brackets.
|
||||
*/
|
||||
private static String constructProviderUrl(String domain,
|
||||
String[] servers) {
|
||||
String path = "";
|
||||
if (!domain.equals(".")) {
|
||||
try {
|
||||
path = "/" + UrlUtil.encode(domain, "ISO-8859-1");
|
||||
} catch (java.io.UnsupportedEncodingException e) {
|
||||
// assert false : "ISO-Latin-1 charset unavailable";
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
if (i > 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append("dns://").append(servers[i]).append(path);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads environment to find URL(s) of initial context.
|
||||
* Default URL is "dns:".
|
||||
*/
|
||||
private static String getInitCtxUrl(Hashtable<?,?> env) {
|
||||
String url = (String) env.get(Context.PROVIDER_URL);
|
||||
return ((url != null) ? url : DEFAULT_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any DNS server that's not permitted to access
|
||||
* @param input the input server[:port] list, must not be null
|
||||
* @param oneIsEnough return output once there exists one ok
|
||||
* @return the filtered list, all non-permitted input removed
|
||||
*/
|
||||
private static List<String> filterNameServers(List<String> input, boolean oneIsEnough) {
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security == null || input == null || input.isEmpty()) {
|
||||
return input;
|
||||
} else {
|
||||
List<String> output = new ArrayList<>();
|
||||
for (String platformServer: input) {
|
||||
int colon = platformServer.indexOf(':',
|
||||
platformServer.indexOf(']') + 1);
|
||||
|
||||
int p = (colon < 0)
|
||||
? DEFAULT_PORT
|
||||
: Integer.parseInt(
|
||||
platformServer.substring(colon + 1));
|
||||
String s = (colon < 0)
|
||||
? platformServer
|
||||
: platformServer.substring(0, colon);
|
||||
try {
|
||||
security.checkConnect(s, p);
|
||||
output.add(platformServer);
|
||||
if (oneIsEnough) {
|
||||
return output;
|
||||
}
|
||||
} catch (SecurityException se) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
602
jdkSrc/jdk8/com/sun/jndi/dns/DnsName.java
Normal file
602
jdkSrc/jdk8/com/sun/jndi/dns/DnsName.java
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* <tt>DnsName</tt> implements compound names for DNS as specified by
|
||||
* RFCs 1034 and 1035, and as updated and clarified by RFCs 1123 and 2181.
|
||||
*
|
||||
* <p> The labels in a domain name correspond to JNDI atomic names.
|
||||
* Each label must be less than 64 octets in length, and only the
|
||||
* optional root label at the end of the name may be 0 octets long.
|
||||
* The sum of the lengths of all labels in a name, plus the number of
|
||||
* non-root labels plus 1, must be less than 256. The textual
|
||||
* representation of a domain name consists of the labels, escaped as
|
||||
* needed, dot-separated, and ordered right-to-left.
|
||||
*
|
||||
* <p> A label consists of a sequence of octets, each of which may
|
||||
* have any value from 0 to 255.
|
||||
*
|
||||
* <p> <em>Host names</em> are a subset of domain names.
|
||||
* Their labels contain only ASCII letters, digits, and hyphens, and
|
||||
* none may begin or end with a hyphen. While names not conforming to
|
||||
* these rules may be valid domain names, they will not be usable by a
|
||||
* number of DNS applications, and should in most cases be avoided.
|
||||
*
|
||||
* <p> DNS does not specify an encoding (such as UTF-8) to use for
|
||||
* octets with non-ASCII values. As of this writing there is some
|
||||
* work going on in this area, but it is not yet finalized.
|
||||
* <tt>DnsName</tt> currently converts any non-ASCII octets into
|
||||
* characters using ISO-LATIN-1 encoding, in effect taking the
|
||||
* value of each octet and storing it directly into the low-order byte
|
||||
* of a Java character and <i>vice versa</i>. As a consequence, no
|
||||
* character in a DNS name will ever have a non-zero high-order byte.
|
||||
* When the work on internationalizing domain names has stabilized
|
||||
* (see for example <i>draft-ietf-idn-idna-10.txt</i>), <tt>DnsName</tt>
|
||||
* may be updated to conform to that work.
|
||||
*
|
||||
* <p> Backslash (<tt>\</tt>) is used as the escape character in the
|
||||
* textual representation of a domain name. The character sequence
|
||||
* `<tt>\DDD</tt>', where <tt>DDD</tt> is a 3-digit decimal number
|
||||
* (with leading zeros if needed), represents the octet whose value
|
||||
* is <tt>DDD</tt>. The character sequence `<tt>\C</tt>', where
|
||||
* <tt>C</tt> is a character other than <tt>'0'</tt> through
|
||||
* <tt>'9'</tt>, represents the octet whose value is that of
|
||||
* <tt>C</tt> (again using ISO-LATIN-1 encoding); this is particularly
|
||||
* useful for escaping <tt>'.'</tt> or backslash itself. Backslash is
|
||||
* otherwise not allowed in a domain name. Note that escape characters
|
||||
* are interpreted when a name is parsed. So, for example, the character
|
||||
* sequences `<tt>S</tt>', `<tt>\S</tt>', and `<tt>\083</tt>' each
|
||||
* represent the same one-octet name. The <tt>toString()</tt> method
|
||||
* does not generally insert escape sequences except where necessary.
|
||||
* If, however, the <tt>DnsName</tt> was constructed using unneeded
|
||||
* escapes, those escapes may appear in the <tt>toString</tt> result.
|
||||
*
|
||||
* <p> Atomic names passed as parameters to methods of
|
||||
* <tt>DnsName</tt>, and those returned by them, are unescaped. So,
|
||||
* for example, <tt>(new DnsName()).add("a.b")</tt> creates an
|
||||
* object representing the one-label domain name <tt>a\.b</tt>, and
|
||||
* calling <tt>get(0)</tt> on this object returns <tt>"a.b"</tt>.
|
||||
*
|
||||
* <p> While DNS names are case-preserving, comparisons between them
|
||||
* are case-insensitive. When comparing names containing non-ASCII
|
||||
* octets, <tt>DnsName</tt> uses case-insensitive comparison
|
||||
* between pairs of ASCII values, and exact binary comparison
|
||||
* otherwise.
|
||||
|
||||
* <p> A <tt>DnsName</tt> instance is not synchronized against
|
||||
* concurrent access by multiple threads.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public final class DnsName implements Name {
|
||||
|
||||
// If non-null, the domain name represented by this DnsName.
|
||||
private String domain = "";
|
||||
|
||||
// The labels of this domain name, as a list of strings. Index 0
|
||||
// corresponds to the leftmost (least significant) label: note that
|
||||
// this is the reverse of the ordering used by the Name interface.
|
||||
private ArrayList<String> labels = new ArrayList<>();
|
||||
|
||||
// The number of octets needed to carry this domain name in a DNS
|
||||
// packet. Equal to the sum of the lengths of each label, plus the
|
||||
// number of non-root labels, plus 1. Must remain less than 256.
|
||||
private short octets = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a <tt>DnsName</tt> representing the empty domain name.
|
||||
*/
|
||||
public DnsName() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <tt>DnsName</tt> representing a given domain name.
|
||||
*
|
||||
* @param name the domain name to parse
|
||||
* @throws InvalidNameException if <tt>name</tt> does not conform
|
||||
* to DNS syntax.
|
||||
*/
|
||||
public DnsName(String name) throws InvalidNameException {
|
||||
parse(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new DnsName with its name components initialized to
|
||||
* the components of "n" in the range [beg,end). Indexing is as
|
||||
* for the Name interface, with 0 being the most significant.
|
||||
*/
|
||||
private DnsName(DnsName n, int beg, int end) {
|
||||
// Compute indexes into "labels", which has least-significant label
|
||||
// at index 0 (opposite to the convention used for "beg" and "end").
|
||||
int b = n.size() - end;
|
||||
int e = n.size() - beg;
|
||||
labels.addAll(n.labels.subList(b, e));
|
||||
|
||||
if (size() == n.size()) {
|
||||
domain = n.domain;
|
||||
octets = n.octets;
|
||||
} else {
|
||||
for (String label: labels) {
|
||||
if (label.length() > 0) {
|
||||
octets += (short) (label.length() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
if (domain == null) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (String label: labels) {
|
||||
if (buf.length() > 0 || label.length() == 0) {
|
||||
buf.append('.');
|
||||
}
|
||||
escape(buf, label);
|
||||
}
|
||||
domain = buf.toString();
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this domain name follow <em>host name</em> syntax?
|
||||
*/
|
||||
public boolean isHostName() {
|
||||
for (String label: labels) {
|
||||
if (!isHostNameLabel(label)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public short getOctets() {
|
||||
return octets;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return labels.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (size() == 0);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = 0;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
h = 31 * h + getKey(i).hashCode();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Name) || (obj instanceof CompositeName)) {
|
||||
return false;
|
||||
}
|
||||
Name n = (Name) obj;
|
||||
return ((size() == n.size()) && // shortcut: do sizes differ?
|
||||
(compareTo(obj) == 0));
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
Name n = (Name) obj;
|
||||
return compareRange(0, size(), n); // never 0 if sizes differ
|
||||
}
|
||||
|
||||
public boolean startsWith(Name n) {
|
||||
return ((size() >= n.size()) &&
|
||||
(compareRange(0, n.size(), n) == 0));
|
||||
}
|
||||
|
||||
public boolean endsWith(Name n) {
|
||||
return ((size() >= n.size()) &&
|
||||
(compareRange(size() - n.size(), size(), n) == 0));
|
||||
}
|
||||
|
||||
public String get(int pos) {
|
||||
if (pos < 0 || pos >= size()) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
int i = size() - pos - 1; // index of "pos" component in "labels"
|
||||
return labels.get(i);
|
||||
}
|
||||
|
||||
public Enumeration<String> getAll() {
|
||||
return new Enumeration<String>() {
|
||||
int pos = 0;
|
||||
public boolean hasMoreElements() {
|
||||
return (pos < size());
|
||||
}
|
||||
public String nextElement() {
|
||||
if (pos < size()) {
|
||||
return get(pos++);
|
||||
}
|
||||
throw new java.util.NoSuchElementException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Name getPrefix(int pos) {
|
||||
return new DnsName(this, 0, pos);
|
||||
}
|
||||
|
||||
public Name getSuffix(int pos) {
|
||||
return new DnsName(this, pos, size());
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
return new DnsName(this, 0, size());
|
||||
}
|
||||
|
||||
public Object remove(int pos) {
|
||||
if (pos < 0 || pos >= size()) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
int i = size() - pos - 1; // index of element to remove in "labels"
|
||||
String label = labels.remove(i);
|
||||
int len = label.length();
|
||||
if (len > 0) {
|
||||
octets -= (short) (len + 1);
|
||||
}
|
||||
domain = null; // invalidate "domain"
|
||||
return label;
|
||||
}
|
||||
|
||||
public Name add(String comp) throws InvalidNameException {
|
||||
return add(size(), comp);
|
||||
}
|
||||
|
||||
public Name add(int pos, String comp) throws InvalidNameException {
|
||||
if (pos < 0 || pos > size()) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
// Check for empty labels: may have only one, and only at end.
|
||||
int len = comp.length();
|
||||
if ((pos > 0 && len == 0) ||
|
||||
(pos == 0 && hasRootLabel())) {
|
||||
throw new InvalidNameException(
|
||||
"Empty label must be the last label in a domain name");
|
||||
}
|
||||
// Check total name length.
|
||||
if (len > 0) {
|
||||
if (octets + len + 1 >= 256) {
|
||||
throw new InvalidNameException("Name too long");
|
||||
}
|
||||
octets += (short) (len + 1);
|
||||
}
|
||||
|
||||
int i = size() - pos; // index for insertion into "labels"
|
||||
verifyLabel(comp);
|
||||
labels.add(i, comp);
|
||||
|
||||
domain = null; // invalidate "domain"
|
||||
return this;
|
||||
}
|
||||
|
||||
public Name addAll(Name suffix) throws InvalidNameException {
|
||||
return addAll(size(), suffix);
|
||||
}
|
||||
|
||||
public Name addAll(int pos, Name n) throws InvalidNameException {
|
||||
if (n instanceof DnsName) {
|
||||
// "n" is a DnsName so we can insert it as a whole, rather than
|
||||
// verifying and inserting it component-by-component.
|
||||
// More code, but less work.
|
||||
DnsName dn = (DnsName) n;
|
||||
|
||||
if (dn.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
// Check for empty labels: may have only one, and only at end.
|
||||
if ((pos > 0 && dn.hasRootLabel()) ||
|
||||
(pos == 0 && hasRootLabel())) {
|
||||
throw new InvalidNameException(
|
||||
"Empty label must be the last label in a domain name");
|
||||
}
|
||||
|
||||
short newOctets = (short) (octets + dn.octets - 1);
|
||||
if (newOctets > 255) {
|
||||
throw new InvalidNameException("Name too long");
|
||||
}
|
||||
octets = newOctets;
|
||||
int i = size() - pos; // index for insertion into "labels"
|
||||
labels.addAll(i, dn.labels);
|
||||
|
||||
// Preserve "domain" if we're appending or prepending,
|
||||
// otherwise invalidate it.
|
||||
if (isEmpty()) {
|
||||
domain = dn.domain;
|
||||
} else if (domain == null || dn.domain == null) {
|
||||
domain = null;
|
||||
} else if (pos == 0) {
|
||||
domain += (dn.domain.equals(".") ? "" : ".") + dn.domain;
|
||||
} else if (pos == size()) {
|
||||
domain = dn.domain + (domain.equals(".") ? "" : ".") + domain;
|
||||
} else {
|
||||
domain = null;
|
||||
}
|
||||
|
||||
} else if (n instanceof CompositeName) {
|
||||
n = (DnsName) n; // force ClassCastException
|
||||
|
||||
} else { // "n" is a compound name, but not a DnsName.
|
||||
// Add labels least-significant first: sometimes more efficient.
|
||||
for (int i = n.size() - 1; i >= 0; i--) {
|
||||
add(pos, n.get(i));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
boolean hasRootLabel() {
|
||||
return (!isEmpty() &&
|
||||
get(0).equals(""));
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper method for public comparison methods. Lexicographically
|
||||
* compares components of this name in the range [beg,end) with
|
||||
* all components of "n". Indexing is as for the Name interface,
|
||||
* with 0 being the most significant. Returns negative, zero, or
|
||||
* positive as these name components are less than, equal to, or
|
||||
* greater than those of "n".
|
||||
*/
|
||||
private int compareRange(int beg, int end, Name n) {
|
||||
if (n instanceof CompositeName) {
|
||||
n = (DnsName) n; // force ClassCastException
|
||||
}
|
||||
// Loop through labels, starting with most significant.
|
||||
int minSize = Math.min(end - beg, n.size());
|
||||
for (int i = 0; i < minSize; i++) {
|
||||
String label1 = get(i + beg);
|
||||
String label2 = n.get(i);
|
||||
|
||||
int j = size() - (i + beg) - 1; // index of label1 in "labels"
|
||||
// assert (label1 == labels.get(j));
|
||||
|
||||
int c = compareLabels(label1, label2);
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return ((end - beg) - n.size()); // longer range wins
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a key suitable for hashing the label at index i.
|
||||
* Indexing is as for the Name interface, with 0 being the most
|
||||
* significant.
|
||||
*/
|
||||
String getKey(int i) {
|
||||
return keyForLabel(get(i));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parses a domain name, setting the values of instance vars accordingly.
|
||||
*/
|
||||
private void parse(String name) throws InvalidNameException {
|
||||
|
||||
StringBuffer label = new StringBuffer(); // label being parsed
|
||||
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
|
||||
if (c == '\\') { // found an escape sequence
|
||||
c = getEscapedOctet(name, i++);
|
||||
if (isDigit(name.charAt(i))) { // sequence is \DDD
|
||||
i += 2; // consume remaining digits
|
||||
}
|
||||
label.append(c);
|
||||
|
||||
} else if (c != '.') { // an unescaped octet
|
||||
label.append(c);
|
||||
|
||||
} else { // found '.' separator
|
||||
add(0, label.toString()); // check syntax, then add label
|
||||
// to end of name
|
||||
label.delete(0, i); // clear buffer for next label
|
||||
}
|
||||
}
|
||||
|
||||
// If name is neither "." nor "", the octets (zero or more)
|
||||
// from the rightmost dot onward are now added as the final
|
||||
// label of the name. Those two are special cases in that for
|
||||
// all other domain names, the number of labels is one greater
|
||||
// than the number of dot separators.
|
||||
if (!name.equals("") && !name.equals(".")) {
|
||||
add(0, label.toString());
|
||||
}
|
||||
|
||||
domain = name; // do this last, since add() sets it to null
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns (as a char) the octet indicated by the escape sequence
|
||||
* at a given position within a domain name.
|
||||
* @throws InvalidNameException if a valid escape sequence is not found.
|
||||
*/
|
||||
private static char getEscapedOctet(String name, int pos)
|
||||
throws InvalidNameException {
|
||||
try {
|
||||
// assert (name.charAt(pos) == '\\');
|
||||
char c1 = name.charAt(++pos);
|
||||
if (isDigit(c1)) { // sequence is `\DDD'
|
||||
char c2 = name.charAt(++pos);
|
||||
char c3 = name.charAt(++pos);
|
||||
if (isDigit(c2) && isDigit(c3)) {
|
||||
return (char)
|
||||
((c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0'));
|
||||
} else {
|
||||
throw new InvalidNameException(
|
||||
"Invalid escape sequence in " + name);
|
||||
}
|
||||
} else { // sequence is `\C'
|
||||
return c1;
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new InvalidNameException(
|
||||
"Invalid escape sequence in " + name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that this label is valid.
|
||||
* @throws InvalidNameException if label is not valid.
|
||||
*/
|
||||
private static void verifyLabel(String label) throws InvalidNameException {
|
||||
if (label.length() > 63) {
|
||||
throw new InvalidNameException(
|
||||
"Label exceeds 63 octets: " + label);
|
||||
}
|
||||
// Check for two-byte characters.
|
||||
for (int i = 0; i < label.length(); i++) {
|
||||
char c = label.charAt(i);
|
||||
if ((c & 0xFF00) != 0) {
|
||||
throw new InvalidNameException(
|
||||
"Label has two-byte char: " + label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Does this label conform to host name syntax?
|
||||
*/
|
||||
private static boolean isHostNameLabel(String label) {
|
||||
for (int i = 0; i < label.length(); i++) {
|
||||
char c = label.charAt(i);
|
||||
if (!isHostNameChar(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !(label.startsWith("-") || label.endsWith("-"));
|
||||
}
|
||||
|
||||
private static boolean isHostNameChar(char c) {
|
||||
return (c == '-' ||
|
||||
c >= 'a' && c <= 'z' ||
|
||||
c >= 'A' && c <= 'Z' ||
|
||||
c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
private static boolean isDigit(char c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a label to buf, escaping as needed.
|
||||
*/
|
||||
private static void escape(StringBuilder buf, String label) {
|
||||
for (int i = 0; i < label.length(); i++) {
|
||||
char c = label.charAt(i);
|
||||
if (c == '.' || c == '\\') {
|
||||
buf.append('\\');
|
||||
}
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two labels, ignoring case for ASCII values.
|
||||
* Returns negative, zero, or positive as the first label
|
||||
* is less than, equal to, or greater than the second.
|
||||
* See keyForLabel().
|
||||
*/
|
||||
private static int compareLabels(String label1, String label2) {
|
||||
int min = Math.min(label1.length(), label2.length());
|
||||
for (int i = 0; i < min; i++) {
|
||||
char c1 = label1.charAt(i);
|
||||
char c2 = label2.charAt(i);
|
||||
if (c1 >= 'A' && c1 <= 'Z') {
|
||||
c1 += 'a' - 'A'; // to lower case
|
||||
}
|
||||
if (c2 >= 'A' && c2 <= 'Z') {
|
||||
c2 += 'a' - 'A'; // to lower case
|
||||
}
|
||||
if (c1 != c2) {
|
||||
return (c1 - c2);
|
||||
}
|
||||
}
|
||||
return (label1.length() - label2.length()); // the longer one wins
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a key suitable for hashing a label. Two labels map to
|
||||
* the same key iff they are equal, taking possible case-folding
|
||||
* into account. See compareLabels().
|
||||
*/
|
||||
private static String keyForLabel(String label) {
|
||||
StringBuffer buf = new StringBuffer(label.length());
|
||||
for (int i = 0; i < label.length(); i++) {
|
||||
char c = label.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 'a' - 'A'; // to lower case
|
||||
}
|
||||
buf.append(c);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes only the domain name string, for compactness and to avoid
|
||||
* any implementation dependency.
|
||||
*
|
||||
* @serialdata The domain name string.
|
||||
*/
|
||||
private void writeObject(java.io.ObjectOutputStream s)
|
||||
throws java.io.IOException {
|
||||
s.writeObject(toString());
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
try {
|
||||
parse((String) s.readObject());
|
||||
} catch (InvalidNameException e) {
|
||||
// shouldn't happen
|
||||
throw new java.io.StreamCorruptedException(
|
||||
"Invalid name: " + domain);
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7040187611324710271L;
|
||||
}
|
||||
55
jdkSrc/jdk8/com/sun/jndi/dns/DnsNameParser.java
Normal file
55
jdkSrc/jdk8/com/sun/jndi/dns/DnsNameParser.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* A name parser for DNS names.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
class DnsNameParser implements NameParser {
|
||||
|
||||
public Name parse(String name) throws NamingException {
|
||||
return new DnsName(name);
|
||||
}
|
||||
|
||||
|
||||
// Every DnsNameParser is created equal.
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof DnsNameParser);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return DnsNameParser.class.hashCode() + 1;
|
||||
}
|
||||
}
|
||||
180
jdkSrc/jdk8/com/sun/jndi/dns/DnsUrl.java
Normal file
180
jdkSrc/jdk8/com/sun/jndi/dns/DnsUrl.java
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.dns;
|
||||
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import com.sun.jndi.toolkit.url.Uri;
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
|
||||
|
||||
/**
|
||||
* A DnsUrl represents a DNS pseudo-URL of the form
|
||||
* <pre>
|
||||
* dns://[host][:port][/[domain]]
|
||||
* or
|
||||
* dns:[/][domain]
|
||||
* </pre>
|
||||
* The host names a DNS server. If the host is not provided, it
|
||||
* indicates that the underlying platform's DNS server(s) should be
|
||||
* used if possible, or that "localhost" should be used otherwise. If
|
||||
* the port is not provided, the DNS default port 53 will be used.
|
||||
* The domain indicates the domain name of the context, and is not
|
||||
* necessarily related to the domain of the server; if it is not
|
||||
* provided, the root domain "." is used. Special characters in
|
||||
* the domain name must be %-escaped as described in RFC 2396.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class DnsUrl extends Uri {
|
||||
|
||||
private static final String PARSE_MODE_PROP = "com.sun.jndi.dnsURLParsing";
|
||||
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
|
||||
|
||||
public static final ParseMode PARSE_MODE;
|
||||
static {
|
||||
PrivilegedAction<String> action =
|
||||
new GetPropertyAction(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
|
||||
ParseMode parseMode = DEFAULT_PARSE_MODE;
|
||||
try {
|
||||
String mode = AccessController.doPrivileged(action);
|
||||
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
} catch (Throwable t) {
|
||||
parseMode = DEFAULT_PARSE_MODE;
|
||||
} finally {
|
||||
PARSE_MODE = parseMode;
|
||||
}
|
||||
}
|
||||
private String domain; // domain name of the context
|
||||
|
||||
|
||||
/**
|
||||
* Given a space-separated list of DNS URLs, returns an array of DnsUrl
|
||||
* objects.
|
||||
*/
|
||||
public static DnsUrl[] fromList(String urlList)
|
||||
throws MalformedURLException {
|
||||
|
||||
DnsUrl[] urls = new DnsUrl[(urlList.length() + 1) / 2];
|
||||
int i = 0; // next available index in urls
|
||||
StringTokenizer st = new StringTokenizer(urlList, " ");
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
try {
|
||||
urls[i++] = new DnsUrl(validateURI(st.nextToken()));
|
||||
} catch (URISyntaxException e) {
|
||||
MalformedURLException mue = new MalformedURLException(e.getMessage());
|
||||
mue.initCause(e);
|
||||
throw mue;
|
||||
}
|
||||
}
|
||||
DnsUrl[] trimmed = new DnsUrl[i];
|
||||
System.arraycopy(urls, 0, trimmed, 0, i);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParseMode parseMode() {
|
||||
return PARSE_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final boolean isSchemeOnly(String uri) {
|
||||
return isDnsSchemeOnly(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkSchemeOnly(String uri, String scheme) {
|
||||
return uri.equals(scheme + ":") || uri.equals(scheme + "://");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final MalformedURLException newInvalidURISchemeException(String uri) {
|
||||
return new MalformedURLException(
|
||||
uri + " is not a valid DNS pseudo-URL");
|
||||
}
|
||||
|
||||
private static boolean isDnsSchemeOnly(String uri) {
|
||||
return "dns:".equals(uri) || "dns://".equals(uri);
|
||||
}
|
||||
|
||||
private static String validateURI(String uri) throws URISyntaxException {
|
||||
// no validation in legacy parsing mode
|
||||
if (PARSE_MODE == ParseMode.LEGACY) return uri;
|
||||
// special case of scheme-only URIs
|
||||
if (isDnsSchemeOnly(uri)) return uri;
|
||||
// use java.net.URI to validate the uri syntax
|
||||
return new URI(uri).toString();
|
||||
}
|
||||
|
||||
public DnsUrl(String url) throws MalformedURLException {
|
||||
super(url);
|
||||
|
||||
if (!scheme.equals("dns")) {
|
||||
throw newInvalidURISchemeException(url);
|
||||
}
|
||||
|
||||
domain = path.startsWith("/")
|
||||
? path.substring(1)
|
||||
: path;
|
||||
domain = domain.equals("")
|
||||
? "."
|
||||
: UrlUtil.decode(domain);
|
||||
|
||||
// Debug
|
||||
// System.out.println("host=" + host + " port=" + port +
|
||||
// " domain=" + domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain of this URL, or "." if none is provided.
|
||||
* Never null.
|
||||
*/
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Debug
|
||||
public static void main(String args[]) throws MalformedURLException {
|
||||
DnsUrl[] urls = fromList(args[0]);
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
System.out.println(urls[i].toString());
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
126
jdkSrc/jdk8/com/sun/jndi/dns/Header.java
Normal file
126
jdkSrc/jdk8/com/sun/jndi/dns/Header.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2002, 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.dns;
|
||||
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* The Header class represents the header of a DNS message.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
class Header {
|
||||
|
||||
static final int HEADER_SIZE = 12; // octets in a DNS header
|
||||
|
||||
// Masks and shift amounts for DNS header flag fields.
|
||||
static final short QR_BIT = (short) 0x8000;
|
||||
static final short OPCODE_MASK = (short) 0x7800;
|
||||
static final int OPCODE_SHIFT = 11;
|
||||
static final short AA_BIT = (short) 0x0400;
|
||||
static final short TC_BIT = (short) 0x0200;
|
||||
static final short RD_BIT = (short) 0x0100;
|
||||
static final short RA_BIT = (short) 0x0080;
|
||||
static final short RCODE_MASK = (short) 0x000F;
|
||||
|
||||
int xid; // ID: 16-bit query identifier
|
||||
boolean query; // QR: true if query, false if response
|
||||
int opcode; // OPCODE: 4-bit opcode
|
||||
boolean authoritative; // AA
|
||||
boolean truncated; // TC
|
||||
boolean recursionDesired; // RD
|
||||
boolean recursionAvail; // RA
|
||||
int rcode; // RCODE: 4-bit response code
|
||||
int numQuestions;
|
||||
int numAnswers;
|
||||
int numAuthorities;
|
||||
int numAdditionals;
|
||||
|
||||
/*
|
||||
* Returns a representation of a decoded DNS message header.
|
||||
* Does not modify or store a reference to the msg array.
|
||||
*/
|
||||
Header(byte[] msg, int msgLen) throws NamingException {
|
||||
decode(msg, msgLen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a DNS message header. Does not modify or store a
|
||||
* reference to the msg array.
|
||||
*/
|
||||
private void decode(byte[] msg, int msgLen) throws NamingException {
|
||||
|
||||
try {
|
||||
int pos = 0; // current offset into msg
|
||||
|
||||
if (msgLen < HEADER_SIZE) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: corrupted message header");
|
||||
}
|
||||
|
||||
xid = getShort(msg, pos);
|
||||
pos += 2;
|
||||
|
||||
// Flags
|
||||
short flags = (short) getShort(msg, pos);
|
||||
pos += 2;
|
||||
query = (flags & QR_BIT) == 0;
|
||||
opcode = (flags & OPCODE_MASK) >>> OPCODE_SHIFT;
|
||||
authoritative = (flags & AA_BIT) != 0;
|
||||
truncated = (flags & TC_BIT) != 0;
|
||||
recursionDesired = (flags & RD_BIT) != 0;
|
||||
recursionAvail = (flags & RA_BIT) != 0;
|
||||
rcode = (flags & RCODE_MASK);
|
||||
|
||||
// RR counts
|
||||
numQuestions = getShort(msg, pos);
|
||||
pos += 2;
|
||||
numAnswers = getShort(msg, pos);
|
||||
pos += 2;
|
||||
numAuthorities = getShort(msg, pos);
|
||||
pos += 2;
|
||||
numAdditionals = getShort(msg, pos);
|
||||
pos += 2;
|
||||
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: corrupted message header");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the 2-byte unsigned value at msg[pos]. The high
|
||||
* order byte comes first.
|
||||
*/
|
||||
private static int getShort(byte[] msg, int pos) {
|
||||
return (((msg[pos] & 0xFF) << 8) |
|
||||
(msg[pos + 1] & 0xFF));
|
||||
}
|
||||
}
|
||||
156
jdkSrc/jdk8/com/sun/jndi/dns/NameNode.java
Normal file
156
jdkSrc/jdk8/com/sun/jndi/dns/NameNode.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
|
||||
/**
|
||||
* A NameNode represents a node in the DNS namespace. Each node
|
||||
* has a label, which is its name relative to its parent (so the
|
||||
* node at Sun.COM has label "Sun"). Each node has a hashtable of
|
||||
* children indexed by their labels converted to lower-case.
|
||||
*
|
||||
* <p> A node may be addressed from another by giving a DnsName
|
||||
* consisting of the sequence of labels from one node to the other.
|
||||
*
|
||||
* <p> Each node also has an <tt>isZoneCut</tt> flag, used to indicate
|
||||
* if the node is a zone cut. A zone cut is a node with an NS record
|
||||
* that is contained in one zone, but that actually belongs to a child zone.
|
||||
*
|
||||
* <p> All access is unsynchronized.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
class NameNode {
|
||||
|
||||
private String label; // name of this node relative to its
|
||||
// parent, or null for root of a tree
|
||||
private Hashtable<String,NameNode> children = null; // child nodes
|
||||
private boolean isZoneCut = false; // true if this node is a zone cut
|
||||
private int depth = 0; // depth in tree (0 for root)
|
||||
|
||||
NameNode(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a newly-allocated NameNode. Used to allocate new nodes
|
||||
* in a tree. Should be overridden in a subclass to return an object
|
||||
* of the subclass's type.
|
||||
*/
|
||||
protected NameNode newNameNode(String label) {
|
||||
return new NameNode(label);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the name of this node relative to its parent, or null for
|
||||
* the root of a tree.
|
||||
*/
|
||||
String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the depth of this node in the tree. The depth of the root
|
||||
* is 0.
|
||||
*/
|
||||
int depth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
boolean isZoneCut() {
|
||||
return isZoneCut;
|
||||
}
|
||||
|
||||
void setZoneCut(boolean isZoneCut) {
|
||||
this.isZoneCut = isZoneCut;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the children of this node, or null if there are none.
|
||||
* The caller must not modify the Hashtable returned.
|
||||
*/
|
||||
Hashtable<String,NameNode> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the child node given the hash key (the down-cased label)
|
||||
* for its name relative to this node, or null if there is no such
|
||||
* child.
|
||||
*/
|
||||
NameNode get(String key) {
|
||||
return (children != null)
|
||||
? children.get(key)
|
||||
: null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the node at the end of a path, or null if the
|
||||
* node does not exist.
|
||||
* The path is specified by the labels of <tt>name</tt>, beginning
|
||||
* at index idx.
|
||||
*/
|
||||
NameNode get(DnsName name, int idx) {
|
||||
NameNode node = this;
|
||||
for (int i = idx; i < name.size() && node != null; i++) {
|
||||
node = node.get(name.getKey(i));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the node at the end of a path, creating it and any
|
||||
* intermediate nodes as needed.
|
||||
* The path is specified by the labels of <tt>name</tt>, beginning
|
||||
* at index idx.
|
||||
*/
|
||||
NameNode add(DnsName name, int idx) {
|
||||
NameNode node = this;
|
||||
for (int i = idx; i < name.size(); i++) {
|
||||
String label = name.get(i);
|
||||
String key = name.getKey(i);
|
||||
|
||||
NameNode child = null;
|
||||
if (node.children == null) {
|
||||
node.children = new Hashtable<>();
|
||||
} else {
|
||||
child = node.children.get(key);
|
||||
}
|
||||
if (child == null) {
|
||||
child = newNameNode(label);
|
||||
child.depth = node.depth + 1;
|
||||
node.children.put(key, child);
|
||||
}
|
||||
node = child;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
190
jdkSrc/jdk8/com/sun/jndi/dns/Resolver.java
Normal file
190
jdkSrc/jdk8/com/sun/jndi/dns/Resolver.java
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* The Resolver class performs DNS client operations in support of DnsContext.
|
||||
*
|
||||
* <p> Every DnsName instance passed to or returned from a method of
|
||||
* this class should be fully-qualified and contain a root label (an
|
||||
* empty component at position 0).
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
class Resolver {
|
||||
|
||||
private DnsClient dnsClient;
|
||||
private int timeout; // initial timeout on UDP queries in ms
|
||||
private int retries; // number of UDP retries
|
||||
|
||||
|
||||
/*
|
||||
* Constructs a new Resolver given its servers and timeout parameters.
|
||||
* Each server is of the form "server[:port]".
|
||||
* IPv6 literal host names include delimiting brackets.
|
||||
* There must be at least one server.
|
||||
* "timeout" is the initial timeout interval (in ms) for UDP queries,
|
||||
* and "retries" gives the number of retries per server.
|
||||
*/
|
||||
Resolver(String[] servers, int timeout, int retries)
|
||||
throws NamingException {
|
||||
this.timeout = timeout;
|
||||
this.retries = retries;
|
||||
dnsClient = new DnsClient(servers, timeout, retries);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
dnsClient.close();
|
||||
dnsClient = null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Queries resource records of a particular class and type for a
|
||||
* given domain name.
|
||||
* Useful values of rrclass are ResourceRecord.[Q]CLASS_xxx.
|
||||
* Useful values of rrtype are ResourceRecord.[Q]TYPE_xxx.
|
||||
* If recursion is true, recursion is requested on the query.
|
||||
* If auth is true, only authoritative responses are accepted.
|
||||
*/
|
||||
ResourceRecords query(DnsName fqdn, int rrclass, int rrtype,
|
||||
boolean recursion, boolean auth)
|
||||
throws NamingException {
|
||||
return dnsClient.query(fqdn, rrclass, rrtype, recursion, auth);
|
||||
}
|
||||
|
||||
/*
|
||||
* Queries all resource records of a zone given its domain name and class.
|
||||
* If recursion is true, recursion is requested on the query to find
|
||||
* the name server (and also on the zone transfer, but it won't matter).
|
||||
*/
|
||||
ResourceRecords queryZone(DnsName zone, int rrclass, boolean recursion)
|
||||
throws NamingException {
|
||||
|
||||
DnsClient cl =
|
||||
new DnsClient(findNameServers(zone, recursion), timeout, retries);
|
||||
try {
|
||||
return cl.queryZone(zone, rrclass, recursion);
|
||||
} finally {
|
||||
cl.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the zone of a given domain name. The method is to look
|
||||
* for the first SOA record on the path from the given domain to
|
||||
* the root. This search may be partially bypassed if the zone's
|
||||
* SOA record is received in the authority section of a response.
|
||||
* If recursion is true, recursion is requested on any queries.
|
||||
*/
|
||||
DnsName findZoneName(DnsName fqdn, int rrclass, boolean recursion)
|
||||
throws NamingException {
|
||||
|
||||
fqdn = (DnsName) fqdn.clone();
|
||||
while (fqdn.size() > 1) { // while below root
|
||||
ResourceRecords rrs = null;
|
||||
try {
|
||||
rrs = query(fqdn, rrclass, ResourceRecord.TYPE_SOA,
|
||||
recursion, false);
|
||||
} catch (NameNotFoundException e) {
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
// Ignore error and keep searching up the tree.
|
||||
}
|
||||
if (rrs != null) {
|
||||
if (rrs.answer.size() > 0) { // found zone's SOA
|
||||
return fqdn;
|
||||
}
|
||||
// Look for an SOA record giving the zone's top node.
|
||||
for (int i = 0; i < rrs.authority.size(); i++) {
|
||||
ResourceRecord rr = rrs.authority.elementAt(i);
|
||||
if (rr.getType() == ResourceRecord.TYPE_SOA) {
|
||||
DnsName zone = rr.getName();
|
||||
if (fqdn.endsWith(zone)) {
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fqdn.remove(fqdn.size() - 1); // one step rootward
|
||||
}
|
||||
return fqdn; // no SOA found below root, so
|
||||
// return root
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds a zone's SOA record. Returns null if no SOA is found (in
|
||||
* which case "zone" is not actually a zone).
|
||||
* If recursion is true, recursion is requested on the query.
|
||||
*/
|
||||
ResourceRecord findSoa(DnsName zone, int rrclass, boolean recursion)
|
||||
throws NamingException {
|
||||
|
||||
ResourceRecords rrs = query(zone, rrclass, ResourceRecord.TYPE_SOA,
|
||||
recursion, false);
|
||||
for (int i = 0; i < rrs.answer.size(); i++) {
|
||||
ResourceRecord rr = rrs.answer.elementAt(i);
|
||||
if (rr.getType() == ResourceRecord.TYPE_SOA) {
|
||||
return rr;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the name servers of a zone. <tt>zone</tt> is a fully-qualified
|
||||
* domain name at the top of a zone.
|
||||
* If recursion is true, recursion is requested on the query.
|
||||
*/
|
||||
private String[] findNameServers(DnsName zone, boolean recursion)
|
||||
throws NamingException {
|
||||
|
||||
// %%% As an optimization, could look in authority section of
|
||||
// findZoneName() response first.
|
||||
ResourceRecords rrs =
|
||||
query(zone, ResourceRecord.CLASS_INTERNET, ResourceRecord.TYPE_NS,
|
||||
recursion, false);
|
||||
String[] ns = new String[rrs.answer.size()];
|
||||
for (int i = 0; i < ns.length; i++) {
|
||||
ResourceRecord rr = rrs.answer.elementAt(i);
|
||||
if (rr.getType() != ResourceRecord.TYPE_NS) {
|
||||
throw new CommunicationException("Corrupted DNS message");
|
||||
}
|
||||
ns[i] = (String) rr.getRdata();
|
||||
|
||||
// Server name will be passed to InetAddress.getByName(), which
|
||||
// may not be able to handle a trailing dot.
|
||||
// assert ns[i].endsWith(".");
|
||||
ns[i] = ns[i].substring(0, ns[i].length() - 1);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
}
|
||||
643
jdkSrc/jdk8/com/sun/jndi/dns/ResourceRecord.java
Normal file
643
jdkSrc/jdk8/com/sun/jndi/dns/ResourceRecord.java
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, 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.dns;
|
||||
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.InvalidNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
/**
|
||||
* The ResourceRecord class represents a DNS resource record.
|
||||
* The string format is based on the master file representation in
|
||||
* RFC 1035.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class ResourceRecord {
|
||||
|
||||
/*
|
||||
* Resource record type codes
|
||||
*/
|
||||
static final int TYPE_A = 1;
|
||||
static final int TYPE_NS = 2;
|
||||
static final int TYPE_CNAME = 5;
|
||||
static final int TYPE_SOA = 6;
|
||||
static final int TYPE_PTR = 12;
|
||||
static final int TYPE_HINFO = 13;
|
||||
static final int TYPE_MX = 15;
|
||||
static final int TYPE_TXT = 16;
|
||||
static final int TYPE_AAAA = 28;
|
||||
static final int TYPE_SRV = 33;
|
||||
static final int TYPE_NAPTR = 35;
|
||||
static final int QTYPE_AXFR = 252; // zone transfer
|
||||
static final int QTYPE_STAR = 255; // query type "*"
|
||||
|
||||
/*
|
||||
* Mapping from resource record type codes to type name strings.
|
||||
*/
|
||||
static final String rrTypeNames[] = {
|
||||
null, "A", "NS", null, null,
|
||||
"CNAME", "SOA", null, null, null,
|
||||
null, null, "PTR", "HINFO", null,
|
||||
"MX", "TXT", null, null, null,
|
||||
null, null, null, null, null,
|
||||
null, null, null, "AAAA", null,
|
||||
null, null, null, "SRV", null,
|
||||
"NAPTR"
|
||||
};
|
||||
|
||||
/*
|
||||
* Resource record class codes
|
||||
*/
|
||||
static final int CLASS_INTERNET = 1;
|
||||
static final int CLASS_HESIOD = 2;
|
||||
static final int QCLASS_STAR = 255; // query class "*"
|
||||
|
||||
/*
|
||||
* Mapping from resource record type codes to class name strings.
|
||||
*/
|
||||
static final String rrClassNames[] = {
|
||||
null, "IN", null, null, "HS"
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of compression references in labels.
|
||||
* Used to detect compression loops.
|
||||
*/
|
||||
private static final int MAXIMUM_COMPRESSION_REFERENCES = 16;
|
||||
|
||||
byte[] msg; // DNS message
|
||||
int msgLen; // msg size (in octets)
|
||||
boolean qSection; // true if this RR is part of question section
|
||||
// and therefore has no ttl or rdata
|
||||
int offset; // offset of RR w/in msg
|
||||
int rrlen; // number of octets in encoded RR
|
||||
DnsName name; // name field of RR, including root label
|
||||
int rrtype; // type field of RR
|
||||
String rrtypeName; // name of of rrtype
|
||||
int rrclass; // class field of RR
|
||||
String rrclassName; // name of rrclass
|
||||
int ttl = 0; // ttl field of RR
|
||||
int rdlen = 0; // number of octets of rdata
|
||||
Object rdata = null; // rdata -- most are String, unknown are byte[]
|
||||
|
||||
|
||||
/*
|
||||
* Constructs a new ResourceRecord. The encoded data of the DNS
|
||||
* message is contained in msg; data for this RR begins at msg[offset].
|
||||
* If qSection is true this RR is part of a question section. It's
|
||||
* not a true resource record in that case, but is treated as if it
|
||||
* were a shortened one (with no ttl or rdata). If decodeRdata is
|
||||
* false, the rdata is not decoded (and getRdata() will return null)
|
||||
* unless this is an SOA record.
|
||||
*
|
||||
* @throws CommunicationException if a decoded domain name isn't valid.
|
||||
* @throws ArrayIndexOutOfBoundsException given certain other corrupt data.
|
||||
*/
|
||||
ResourceRecord(byte[] msg, int msgLen, int offset,
|
||||
boolean qSection, boolean decodeRdata)
|
||||
throws CommunicationException {
|
||||
|
||||
this.msg = msg;
|
||||
this.msgLen = msgLen;
|
||||
this.offset = offset;
|
||||
this.qSection = qSection;
|
||||
decode(decodeRdata);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String text = name + " " + rrclassName + " " + rrtypeName;
|
||||
if (!qSection) {
|
||||
text += " " + ttl + " " +
|
||||
((rdata != null) ? rdata : "[n/a]");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the name field of this RR, including the root label.
|
||||
*/
|
||||
public DnsName getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of octets in the encoded RR.
|
||||
*/
|
||||
public int size() {
|
||||
return rrlen;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return rrtype;
|
||||
}
|
||||
|
||||
public int getRrclass() {
|
||||
return rrclass;
|
||||
}
|
||||
|
||||
public Object getRdata() {
|
||||
return rdata;
|
||||
}
|
||||
|
||||
|
||||
public static String getTypeName(int rrtype) {
|
||||
return valueToName(rrtype, rrTypeNames);
|
||||
}
|
||||
|
||||
public static int getType(String typeName) {
|
||||
return nameToValue(typeName, rrTypeNames);
|
||||
}
|
||||
|
||||
public static String getRrclassName(int rrclass) {
|
||||
return valueToName(rrclass, rrClassNames);
|
||||
}
|
||||
|
||||
public static int getRrclass(String className) {
|
||||
return nameToValue(className, rrClassNames);
|
||||
}
|
||||
|
||||
private static String valueToName(int val, String[] names) {
|
||||
String name = null;
|
||||
if ((val > 0) && (val < names.length)) {
|
||||
name = names[val];
|
||||
} else if (val == QTYPE_STAR) { // QTYPE_STAR == QCLASS_STAR
|
||||
name = "*";
|
||||
}
|
||||
if (name == null) {
|
||||
name = Integer.toString(val);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private static int nameToValue(String name, String[] names) {
|
||||
if (name.equals("")) {
|
||||
return -1; // invalid name
|
||||
} else if (name.equals("*")) {
|
||||
return QTYPE_STAR; // QTYPE_STAR == QCLASS_STAR
|
||||
}
|
||||
if (Character.isDigit(name.charAt(0))) {
|
||||
try {
|
||||
return Integer.parseInt(name);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < names.length; i++) {
|
||||
if ((names[i] != null) &&
|
||||
name.equalsIgnoreCase(names[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // unknown name
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two SOA record serial numbers using 32-bit serial number
|
||||
* arithmetic as defined in RFC 1982. Serial numbers are unsigned
|
||||
* 32-bit quantities. Returns a negative, zero, or positive value
|
||||
* as the first serial number is less than, equal to, or greater
|
||||
* than the second. If the serial numbers are not comparable the
|
||||
* result is undefined. Note that the relation is not transitive.
|
||||
*/
|
||||
public static int compareSerialNumbers(long s1, long s2) {
|
||||
long diff = s2 - s1;
|
||||
if (diff == 0) {
|
||||
return 0;
|
||||
} else if ((diff > 0 && diff <= 0x7FFFFFFF) ||
|
||||
(diff < 0 && -diff > 0x7FFFFFFF)) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decodes the binary format of the RR.
|
||||
* May throw ArrayIndexOutOfBoundsException given corrupt data.
|
||||
*/
|
||||
private void decode(boolean decodeRdata) throws CommunicationException {
|
||||
int pos = offset; // index of next unread octet
|
||||
|
||||
name = new DnsName(); // NAME
|
||||
pos = decodeName(pos, name);
|
||||
|
||||
rrtype = getUShort(pos); // TYPE
|
||||
rrtypeName = (rrtype < rrTypeNames.length)
|
||||
? rrTypeNames[rrtype]
|
||||
: null;
|
||||
if (rrtypeName == null) {
|
||||
rrtypeName = Integer.toString(rrtype);
|
||||
}
|
||||
pos += 2;
|
||||
|
||||
rrclass = getUShort(pos); // CLASS
|
||||
rrclassName = (rrclass < rrClassNames.length)
|
||||
? rrClassNames[rrclass]
|
||||
: null;
|
||||
if (rrclassName == null) {
|
||||
rrclassName = Integer.toString(rrclass);
|
||||
}
|
||||
pos += 2;
|
||||
|
||||
if (!qSection) {
|
||||
ttl = getInt(pos); // TTL
|
||||
pos += 4;
|
||||
|
||||
rdlen = getUShort(pos); // RDLENGTH
|
||||
pos += 2;
|
||||
|
||||
rdata = (decodeRdata || // RDATA
|
||||
(rrtype == TYPE_SOA))
|
||||
? decodeRdata(pos)
|
||||
: null;
|
||||
if (rdata instanceof DnsName) {
|
||||
rdata = rdata.toString();
|
||||
}
|
||||
pos += rdlen;
|
||||
}
|
||||
|
||||
rrlen = pos - offset;
|
||||
|
||||
msg = null; // free up for GC
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the 1-byte unsigned value at msg[pos].
|
||||
*/
|
||||
private int getUByte(int pos) {
|
||||
return (msg[pos] & 0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the 2-byte unsigned value at msg[pos]. The high
|
||||
* order byte comes first.
|
||||
*/
|
||||
private int getUShort(int pos) {
|
||||
return (((msg[pos] & 0xFF) << 8) |
|
||||
(msg[pos + 1] & 0xFF));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the 4-byte signed value at msg[pos]. The high
|
||||
* order byte comes first.
|
||||
*/
|
||||
private int getInt(int pos) {
|
||||
return ((getUShort(pos) << 16) | getUShort(pos + 2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the 4-byte unsigned value at msg[pos]. The high
|
||||
* order byte comes first.
|
||||
*/
|
||||
private long getUInt(int pos) {
|
||||
return (getInt(pos) & 0xffffffffL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the name encoded at msg[pos], including the root label.
|
||||
*/
|
||||
private DnsName decodeName(int pos) throws CommunicationException {
|
||||
DnsName n = new DnsName();
|
||||
decodeName(pos, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepends to "n" the domain name encoded at msg[pos], including the root
|
||||
* label. Returns the index into "msg" following the name.
|
||||
*/
|
||||
private int decodeName(int pos, DnsName n) throws CommunicationException {
|
||||
int endPos = -1;
|
||||
int level = 0;
|
||||
try {
|
||||
while (true) {
|
||||
if (level > MAXIMUM_COMPRESSION_REFERENCES)
|
||||
throw new IOException("Too many compression references");
|
||||
int typeAndLen = msg[pos] & 0xFF;
|
||||
if (typeAndLen == 0) { // end of name
|
||||
++pos;
|
||||
n.add(0, "");
|
||||
break;
|
||||
} else if (typeAndLen <= 63) { // regular label
|
||||
++pos;
|
||||
n.add(0, new String(msg, pos, typeAndLen,
|
||||
StandardCharsets.ISO_8859_1));
|
||||
pos += typeAndLen;
|
||||
} else if ((typeAndLen & 0xC0) == 0xC0) { // name compression
|
||||
++level;
|
||||
// cater for the case where the name pointed to is itself
|
||||
// compressed: we don't want endPos to be reset by the second
|
||||
// compression level.
|
||||
int ppos = pos;
|
||||
if (endPos == -1) endPos = pos + 2;
|
||||
pos = getUShort(pos) & 0x3FFF;
|
||||
if (debug) {
|
||||
dprint("decode: name compression at " + ppos
|
||||
+ " -> " + pos + " endPos=" + endPos);
|
||||
assert endPos > 0;
|
||||
assert pos < ppos;
|
||||
assert pos >= Header.HEADER_SIZE;
|
||||
}
|
||||
} else
|
||||
throw new IOException("Invalid label type: " + typeAndLen);
|
||||
}
|
||||
} catch (IOException | InvalidNameException e) {
|
||||
CommunicationException ce =new CommunicationException(
|
||||
"DNS error: malformed packet");
|
||||
ce.initCause(e);
|
||||
throw ce;
|
||||
}
|
||||
if (endPos == -1)
|
||||
endPos = pos;
|
||||
return endPos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata encoded at msg[pos]. The format is dependent
|
||||
* on the rrtype and rrclass values, which have already been set.
|
||||
* The length of the encoded data is rdlen, which has already been
|
||||
* set.
|
||||
* The rdata of records with unknown type/class combinations is
|
||||
* returned in a newly-allocated byte array.
|
||||
*/
|
||||
private Object decodeRdata(int pos) throws CommunicationException {
|
||||
if (rrclass == CLASS_INTERNET) {
|
||||
switch (rrtype) {
|
||||
case TYPE_A:
|
||||
return decodeA(pos);
|
||||
case TYPE_AAAA:
|
||||
return decodeAAAA(pos);
|
||||
case TYPE_CNAME:
|
||||
case TYPE_NS:
|
||||
case TYPE_PTR:
|
||||
return decodeName(pos);
|
||||
case TYPE_MX:
|
||||
return decodeMx(pos);
|
||||
case TYPE_SOA:
|
||||
return decodeSoa(pos);
|
||||
case TYPE_SRV:
|
||||
return decodeSrv(pos);
|
||||
case TYPE_NAPTR:
|
||||
return decodeNaptr(pos);
|
||||
case TYPE_TXT:
|
||||
return decodeTxt(pos);
|
||||
case TYPE_HINFO:
|
||||
return decodeHinfo(pos);
|
||||
}
|
||||
}
|
||||
// Unknown RR type/class
|
||||
if (debug) {
|
||||
dprint("Unknown RR type for RR data: " + rrtype + " rdlen=" + rdlen
|
||||
+ ", pos=" + pos +", msglen=" + msg.length + ", remaining="
|
||||
+ (msg.length-pos));
|
||||
}
|
||||
byte[] rd = new byte[rdlen];
|
||||
System.arraycopy(msg, pos, rd, 0, rdlen);
|
||||
return rd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an MX record that is encoded at msg[pos].
|
||||
*/
|
||||
private String decodeMx(int pos) throws CommunicationException {
|
||||
int preference = getUShort(pos);
|
||||
pos += 2;
|
||||
DnsName name = decodeName(pos);
|
||||
return (preference + " " + name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an SOA record that is encoded at msg[pos].
|
||||
*/
|
||||
private String decodeSoa(int pos) throws CommunicationException {
|
||||
DnsName mname = new DnsName();
|
||||
pos = decodeName(pos, mname);
|
||||
DnsName rname = new DnsName();
|
||||
pos = decodeName(pos, rname);
|
||||
|
||||
long serial = getUInt(pos);
|
||||
pos += 4;
|
||||
long refresh = getUInt(pos);
|
||||
pos += 4;
|
||||
long retry = getUInt(pos);
|
||||
pos += 4;
|
||||
long expire = getUInt(pos);
|
||||
pos += 4;
|
||||
long minimum = getUInt(pos); // now used as negative TTL
|
||||
pos += 4;
|
||||
|
||||
return (mname + " " + rname + " " + serial + " " +
|
||||
refresh + " " + retry + " " + expire + " " + minimum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an SRV record that is encoded at msg[pos].
|
||||
* See RFC 2782.
|
||||
*/
|
||||
private String decodeSrv(int pos) throws CommunicationException {
|
||||
int priority = getUShort(pos);
|
||||
pos += 2;
|
||||
int weight = getUShort(pos);
|
||||
pos += 2;
|
||||
int port = getUShort(pos);
|
||||
pos += 2;
|
||||
DnsName target = decodeName(pos);
|
||||
return (priority + " " + weight + " " + port + " " + target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an NAPTR record that is encoded at msg[pos].
|
||||
* See RFC 2915.
|
||||
*/
|
||||
private String decodeNaptr(int pos) throws CommunicationException {
|
||||
int order = getUShort(pos);
|
||||
pos += 2;
|
||||
int preference = getUShort(pos);
|
||||
pos += 2;
|
||||
StringBuffer flags = new StringBuffer();
|
||||
pos += decodeCharString(pos, flags);
|
||||
StringBuffer services = new StringBuffer();
|
||||
pos += decodeCharString(pos, services);
|
||||
StringBuffer regexp = new StringBuffer(rdlen);
|
||||
pos += decodeCharString(pos, regexp);
|
||||
DnsName replacement = decodeName(pos);
|
||||
|
||||
return (order + " " + preference + " " + flags + " " +
|
||||
services + " " + regexp + " " + replacement);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of a TXT record that is encoded at msg[pos].
|
||||
* The rdata consists of one or more <character-string>s.
|
||||
*/
|
||||
private String decodeTxt(int pos) {
|
||||
StringBuffer buf = new StringBuffer(rdlen);
|
||||
int end = pos + rdlen;
|
||||
while (pos < end) {
|
||||
pos += decodeCharString(pos, buf);
|
||||
if (pos < end) {
|
||||
buf.append(' ');
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an HINFO record that is encoded at msg[pos].
|
||||
* The rdata consists of two <character-string>s.
|
||||
*/
|
||||
private String decodeHinfo(int pos) {
|
||||
StringBuffer buf = new StringBuffer(rdlen);
|
||||
pos += decodeCharString(pos, buf);
|
||||
buf.append(' ');
|
||||
pos += decodeCharString(pos, buf);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes the <character-string> at msg[pos] and adds it to buf.
|
||||
* If the string contains one of the meta-characters ' ', '\\', or
|
||||
* '"', then the result is quoted and any embedded '\\' or '"'
|
||||
* chars are escaped with '\\'. Empty strings are also quoted.
|
||||
* Returns the size of the encoded string, including the initial
|
||||
* length octet.
|
||||
*/
|
||||
private int decodeCharString(int pos, StringBuffer buf) {
|
||||
int start = buf.length(); // starting index of this string
|
||||
int len = getUByte(pos++); // encoded string length
|
||||
boolean quoted = (len == 0); // quote string if empty
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = getUByte(pos++);
|
||||
quoted |= (c == ' ');
|
||||
if ((c == '\\') || (c == '"')) {
|
||||
quoted = true;
|
||||
buf.append('\\');
|
||||
}
|
||||
buf.append((char) c);
|
||||
}
|
||||
if (quoted) {
|
||||
buf.insert(start, '"');
|
||||
buf.append('"');
|
||||
}
|
||||
return (len + 1); // size includes initial octet
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an A record, in dotted-decimal format,
|
||||
* that is encoded at msg[pos].
|
||||
*/
|
||||
private String decodeA(int pos) {
|
||||
return ((msg[pos] & 0xff) + "." +
|
||||
(msg[pos + 1] & 0xff) + "." +
|
||||
(msg[pos + 2] & 0xff) + "." +
|
||||
(msg[pos + 3] & 0xff));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the rdata of an AAAA record, in colon-separated format,
|
||||
* that is encoded at msg[pos]. For example: 4321:0:1:2:3:4:567:89ab.
|
||||
* See RFCs 1886 and 2373.
|
||||
*/
|
||||
private String decodeAAAA(int pos) {
|
||||
int[] addr6 = new int[8]; // the unsigned 16-bit words of the address
|
||||
for (int i = 0; i < 8; i++) {
|
||||
addr6[i] = getUShort(pos);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
// Find longest sequence of two or more zeros, to compress them.
|
||||
int curBase = -1;
|
||||
int curLen = 0;
|
||||
int bestBase = -1;
|
||||
int bestLen = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (addr6[i] == 0) {
|
||||
if (curBase == -1) { // new sequence
|
||||
curBase = i;
|
||||
curLen = 1;
|
||||
} else { // extend sequence
|
||||
++curLen;
|
||||
if ((curLen >= 2) && (curLen > bestLen)) {
|
||||
bestBase = curBase;
|
||||
bestLen = curLen;
|
||||
}
|
||||
}
|
||||
} else { // not in sequence
|
||||
curBase = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// If addr begins with at least 6 zeros and is not :: or ::1,
|
||||
// or with 5 zeros followed by 0xffff, use the text format for
|
||||
// IPv4-compatible or IPv4-mapped addresses.
|
||||
if (bestBase == 0) {
|
||||
if ((bestLen == 6) ||
|
||||
((bestLen == 7) && (addr6[7] > 1))) {
|
||||
return ("::" + decodeA(pos - 4));
|
||||
} else if ((bestLen == 5) && (addr6[5] == 0xffff)) {
|
||||
return ("::ffff:" + decodeA(pos - 4));
|
||||
}
|
||||
}
|
||||
|
||||
// If bestBase != -1, compress zeros in [bestBase, bestBase+bestLen)
|
||||
boolean compress = (bestBase != -1);
|
||||
|
||||
StringBuffer buf = new StringBuffer(40);
|
||||
if (bestBase == 0) {
|
||||
buf.append(':');
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (!compress || (i < bestBase) || (i >= bestBase + bestLen)) {
|
||||
buf.append(Integer.toHexString(addr6[i]));
|
||||
if (i < 7) {
|
||||
buf.append(':');
|
||||
}
|
||||
} else if (compress && (i == bestBase)) { // first compressed zero
|
||||
buf.append(':');
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
private static void dprint(String mess) {
|
||||
if (debug) {
|
||||
System.err.println("DNS: " + mess);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
140
jdkSrc/jdk8/com/sun/jndi/dns/ResourceRecords.java
Normal file
140
jdkSrc/jdk8/com/sun/jndi/dns/ResourceRecords.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* The ResourceRecords class represents the resource records in the
|
||||
* four sections of a DNS message.
|
||||
*
|
||||
* The additional records section is currently ignored.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
class ResourceRecords {
|
||||
|
||||
// Four sections: question, answer, authority, additional.
|
||||
// The question section is treated as being made up of (shortened)
|
||||
// resource records, although this isn't technically how it's defined.
|
||||
Vector<ResourceRecord> question = new Vector<>();
|
||||
Vector<ResourceRecord> answer = new Vector<>();
|
||||
Vector<ResourceRecord> authority = new Vector<>();
|
||||
Vector<ResourceRecord> additional = new Vector<>();
|
||||
|
||||
/*
|
||||
* True if these resource records are from a zone transfer. In
|
||||
* that case only answer records are read (as per
|
||||
* draft-ietf-dnsext-axfr-clarify-02.txt). Also, the rdata of
|
||||
* those answer records is not decoded (for efficiency) except
|
||||
* for SOA records.
|
||||
*/
|
||||
boolean zoneXfer;
|
||||
|
||||
/*
|
||||
* Returns a representation of the resource records in a DNS message.
|
||||
* Does not modify or store a reference to the msg array.
|
||||
*/
|
||||
ResourceRecords(byte[] msg, int msgLen, Header hdr, boolean zoneXfer)
|
||||
throws NamingException {
|
||||
if (zoneXfer) {
|
||||
answer.ensureCapacity(8192); // an arbitrary "large" number
|
||||
}
|
||||
this.zoneXfer = zoneXfer;
|
||||
add(msg, msgLen, hdr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the type field of the first answer record, or -1 if
|
||||
* there are no answer records.
|
||||
*/
|
||||
int getFirstAnsType() {
|
||||
if (answer.size() == 0) {
|
||||
return -1;
|
||||
}
|
||||
return answer.firstElement().getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the type field of the last answer record, or -1 if
|
||||
* there are no answer records.
|
||||
*/
|
||||
int getLastAnsType() {
|
||||
if (answer.size() == 0) {
|
||||
return -1;
|
||||
}
|
||||
return answer.lastElement().getType();
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes the resource records in a DNS message and adds
|
||||
* them to this object.
|
||||
* Does not modify or store a reference to the msg array.
|
||||
*/
|
||||
void add(byte[] msg, int msgLen, Header hdr) throws NamingException {
|
||||
|
||||
ResourceRecord rr;
|
||||
int pos = Header.HEADER_SIZE; // current offset into msg
|
||||
|
||||
try {
|
||||
for (int i = 0; i < hdr.numQuestions; i++) {
|
||||
rr = new ResourceRecord(msg, msgLen, pos, true, false);
|
||||
if (!zoneXfer) {
|
||||
question.addElement(rr);
|
||||
}
|
||||
pos += rr.size();
|
||||
}
|
||||
|
||||
for (int i = 0; i < hdr.numAnswers; i++) {
|
||||
rr = new ResourceRecord(
|
||||
msg, msgLen, pos, false, !zoneXfer);
|
||||
answer.addElement(rr);
|
||||
pos += rr.size();
|
||||
}
|
||||
|
||||
if (zoneXfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < hdr.numAuthorities; i++) {
|
||||
rr = new ResourceRecord(msg, msgLen, pos, false, true);
|
||||
authority.addElement(rr);
|
||||
pos += rr.size();
|
||||
}
|
||||
|
||||
// The additional records section is currently ignored.
|
||||
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new CommunicationException(
|
||||
"DNS error: corrupted message");
|
||||
}
|
||||
}
|
||||
}
|
||||
205
jdkSrc/jdk8/com/sun/jndi/dns/ZoneNode.java
Normal file
205
jdkSrc/jdk8/com/sun/jndi/dns/ZoneNode.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.dns;
|
||||
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Date;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* ZoneNode extends NameNode to represent a tree of the zones in the
|
||||
* DNS namespace, along with any intermediate nodes between zones.
|
||||
* A ZoneNode that represents a zone may be "populated" with a
|
||||
* NameNode tree containing the zone's contents.
|
||||
*
|
||||
* <p> A populated zone's contents will be flagged as having expired after
|
||||
* the time specified by the minimum TTL value in the zone's SOA record.
|
||||
*
|
||||
* <p> Since zone cuts aren't directly modeled by a tree of ZoneNodes,
|
||||
* ZoneNode.isZoneCut() always returns false.
|
||||
*
|
||||
* <p> The synchronization strategy is documented in DnsContext.java.
|
||||
*
|
||||
* <p> The zone's contents are accessed via a soft reference, so its
|
||||
* heap space may be reclaimed when necessary. The zone may be
|
||||
* repopulated later.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
class ZoneNode extends NameNode {
|
||||
|
||||
private SoftReference<NameNode> contentsRef = null; // the zone's namespace
|
||||
private long serialNumber = -1; // the zone data's serial number
|
||||
private Date expiration = null; // time when the zone's data expires
|
||||
|
||||
ZoneNode(String label) {
|
||||
super(label);
|
||||
}
|
||||
|
||||
protected NameNode newNameNode(String label) {
|
||||
return new ZoneNode(label);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears the contents of this node. If the node was flagged as
|
||||
* expired, it remains so.
|
||||
*/
|
||||
synchronized void depopulate() {
|
||||
contentsRef = null;
|
||||
serialNumber = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this node currently populated?
|
||||
*/
|
||||
synchronized boolean isPopulated() {
|
||||
return (getContents() != null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the zone's contents, or null if the zone is not populated.
|
||||
*/
|
||||
synchronized NameNode getContents() {
|
||||
return (contentsRef != null)
|
||||
? contentsRef.get()
|
||||
: null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Has this zone's data expired?
|
||||
*/
|
||||
synchronized boolean isExpired() {
|
||||
return ((expiration != null) && expiration.before(new Date()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the deepest populated zone on the path specified by a
|
||||
* fully-qualified domain name, or null if there is no populated
|
||||
* zone on that path. Note that a node may be depopulated after
|
||||
* being returned.
|
||||
*/
|
||||
ZoneNode getDeepestPopulated(DnsName fqdn) {
|
||||
ZoneNode znode = this;
|
||||
ZoneNode popNode = isPopulated() ? this : null;
|
||||
for (int i = 1; i < fqdn.size(); i++) { // "i=1" to skip root label
|
||||
znode = (ZoneNode) znode.get(fqdn.getKey(i));
|
||||
if (znode == null) {
|
||||
break;
|
||||
} else if (znode.isPopulated()) {
|
||||
popNode = znode;
|
||||
}
|
||||
}
|
||||
return popNode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates (or repopulates) a zone given its own fully-qualified
|
||||
* name and its resource records. Returns the zone's new contents.
|
||||
*/
|
||||
NameNode populate(DnsName zone, ResourceRecords rrs) {
|
||||
// assert zone.get(0).equals(""); // zone has root label
|
||||
// assert (zone.size() == (depth() + 1)); // +1 due to root label
|
||||
|
||||
NameNode newContents = new NameNode(null);
|
||||
|
||||
for (int i = 0; i < rrs.answer.size(); i++) {
|
||||
ResourceRecord rr = rrs.answer.elementAt(i);
|
||||
DnsName n = rr.getName();
|
||||
|
||||
// Ignore resource records whose names aren't within the zone's
|
||||
// domain. Also skip records of the zone's top node, since
|
||||
// the zone's root NameNode is already in place.
|
||||
if ((n.size() > zone.size()) && n.startsWith(zone)) {
|
||||
NameNode nnode = newContents.add(n, zone.size());
|
||||
if (rr.getType() == ResourceRecord.TYPE_NS) {
|
||||
nnode.setZoneCut(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The zone's SOA record is the first record in the answer section.
|
||||
ResourceRecord soa = rrs.answer.firstElement();
|
||||
synchronized (this) {
|
||||
contentsRef = new SoftReference<NameNode>(newContents);
|
||||
serialNumber = getSerialNumber(soa);
|
||||
setExpiration(getMinimumTtl(soa));
|
||||
return newContents;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set this zone's data to expire in <tt>secsToExpiration</tt> seconds.
|
||||
*/
|
||||
private void setExpiration(long secsToExpiration) {
|
||||
expiration = new Date(System.currentTimeMillis() +
|
||||
1000 * secsToExpiration);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an SOA record's minimum TTL field.
|
||||
*/
|
||||
private static long getMinimumTtl(ResourceRecord soa) {
|
||||
String rdata = (String) soa.getRdata();
|
||||
int pos = rdata.lastIndexOf(' ') + 1;
|
||||
return Long.parseLong(rdata.substring(pos));
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares this zone's serial number with that of an SOA record.
|
||||
* Zone must be populated.
|
||||
* Returns a negative, zero, or positive integer as this zone's
|
||||
* serial number is less than, equal to, or greater than the SOA
|
||||
* record's.
|
||||
* See ResourceRecord.compareSerialNumbers() for a description of
|
||||
* serial number arithmetic.
|
||||
*/
|
||||
int compareSerialNumberTo(ResourceRecord soa) {
|
||||
// assert isPopulated();
|
||||
return ResourceRecord.compareSerialNumbers(serialNumber,
|
||||
getSerialNumber(soa));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an SOA record's serial number.
|
||||
*/
|
||||
private static long getSerialNumber(ResourceRecord soa) {
|
||||
String rdata = (String) soa.getRdata();
|
||||
|
||||
// An SOA record ends with: serial refresh retry expire minimum.
|
||||
// Set "beg" to the space before serial, and "end" to the space after.
|
||||
// We go "backward" to avoid dealing with escaped spaces in names.
|
||||
int beg = rdata.length();
|
||||
int end = -1;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
end = beg;
|
||||
beg = rdata.lastIndexOf(' ', end - 1);
|
||||
}
|
||||
return Long.parseLong(rdata.substring(beg + 1, end));
|
||||
}
|
||||
}
|
||||
408
jdkSrc/jdk8/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java
Normal file
408
jdkSrc/jdk8/com/sun/jndi/ldap/AbstractLdapNamingEnumeration.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Basic enumeration for NameClassPair, Binding, and SearchResults.
|
||||
*/
|
||||
|
||||
abstract class AbstractLdapNamingEnumeration<T extends NameClassPair>
|
||||
implements NamingEnumeration<T>, ReferralEnumeration<T> {
|
||||
|
||||
protected Name listArg;
|
||||
|
||||
private boolean cleaned = false;
|
||||
private LdapResult res;
|
||||
private LdapClient enumClnt;
|
||||
private Continuation cont; // used to fill in exceptions
|
||||
private Vector<LdapEntry> entries = null;
|
||||
private int limit = 0;
|
||||
private int posn = 0;
|
||||
protected LdapCtx homeCtx;
|
||||
private LdapReferralException refEx = null;
|
||||
private NamingException errEx = null;
|
||||
|
||||
/*
|
||||
* Record the next set of entries and/or referrals.
|
||||
*/
|
||||
AbstractLdapNamingEnumeration(LdapCtx homeCtx, LdapResult answer, Name listArg,
|
||||
Continuation cont) throws NamingException {
|
||||
|
||||
// These checks are to accommodate referrals and limit exceptions
|
||||
// which will generate an enumeration and defer the exception
|
||||
// to be thrown at the end of the enumeration.
|
||||
// All other exceptions are thrown immediately.
|
||||
// Exceptions shouldn't be thrown here anyhow because
|
||||
// process_return_code() is called before the constructor
|
||||
// is called, so these are just safety checks.
|
||||
|
||||
if ((answer.status != LdapClient.LDAP_SUCCESS) &&
|
||||
(answer.status != LdapClient.LDAP_SIZE_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_TIME_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_ADMIN_LIMIT_EXCEEDED) &&
|
||||
(answer.status != LdapClient.LDAP_REFERRAL) &&
|
||||
(answer.status != LdapClient.LDAP_PARTIAL_RESULTS)) {
|
||||
|
||||
// %%% need to deal with referral
|
||||
NamingException e = new NamingException(
|
||||
LdapClient.getErrorMessage(
|
||||
answer.status, answer.errorMessage));
|
||||
|
||||
throw cont.fillInException(e);
|
||||
}
|
||||
|
||||
// otherwise continue
|
||||
|
||||
res = answer;
|
||||
entries = answer.entries;
|
||||
limit = (entries == null) ? 0 : entries.size(); // handle empty set
|
||||
this.listArg = listArg;
|
||||
this.cont = cont;
|
||||
|
||||
if (answer.refEx != null) {
|
||||
refEx = answer.refEx;
|
||||
}
|
||||
|
||||
// Ensures that context won't get closed from underneath us
|
||||
this.homeCtx = homeCtx;
|
||||
homeCtx.incEnumCount();
|
||||
enumClnt = homeCtx.clnt; // remember
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T nextElement() {
|
||||
try {
|
||||
return next();
|
||||
} catch (NamingException e) {
|
||||
// can't throw exception
|
||||
cleanup();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasMoreElements() {
|
||||
try {
|
||||
return hasMore();
|
||||
} catch (NamingException e) {
|
||||
// can't throw exception
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next set of entries and/or referrals.
|
||||
*/
|
||||
private void getNextBatch() throws NamingException {
|
||||
|
||||
res = homeCtx.getSearchReply(enumClnt, res);
|
||||
if (res == null) {
|
||||
limit = posn = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
entries = res.entries;
|
||||
limit = (entries == null) ? 0 : entries.size(); // handle empty set
|
||||
posn = 0; // reset
|
||||
|
||||
// mimimize the number of calls to processReturnCode()
|
||||
// (expensive when batchSize is small and there are many results)
|
||||
if ((res.status != LdapClient.LDAP_SUCCESS) ||
|
||||
((res.status == LdapClient.LDAP_SUCCESS) &&
|
||||
(res.referrals != null))) {
|
||||
|
||||
try {
|
||||
// convert referrals into a chain of LdapReferralException
|
||||
homeCtx.processReturnCode(res, listArg);
|
||||
|
||||
} catch (LimitExceededException | PartialResultException e) {
|
||||
setNamingException(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// merge any newly received referrals with any current referrals
|
||||
if (res.refEx != null) {
|
||||
if (refEx == null) {
|
||||
refEx = res.refEx;
|
||||
} else {
|
||||
refEx = refEx.appendUnprocessedReferrals(res.refEx);
|
||||
}
|
||||
res.refEx = null; // reset
|
||||
}
|
||||
|
||||
if (res.resControls != null) {
|
||||
homeCtx.respCtls = res.resControls;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean more = true; // assume we have something to start with
|
||||
private boolean hasMoreCalled = false;
|
||||
|
||||
/*
|
||||
* Test if unprocessed entries or referrals exist.
|
||||
*/
|
||||
@Override
|
||||
public final boolean hasMore() throws NamingException {
|
||||
|
||||
if (hasMoreCalled) {
|
||||
return more;
|
||||
}
|
||||
|
||||
hasMoreCalled = true;
|
||||
|
||||
if (!more) {
|
||||
return false;
|
||||
} else {
|
||||
return (more = hasMoreImpl());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next entry.
|
||||
*/
|
||||
@Override
|
||||
public final T next() throws NamingException {
|
||||
|
||||
if (!hasMoreCalled) {
|
||||
hasMore();
|
||||
}
|
||||
hasMoreCalled = false;
|
||||
return nextImpl();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if unprocessed entries or referrals exist.
|
||||
*/
|
||||
private boolean hasMoreImpl() throws NamingException {
|
||||
// when page size is supported, this
|
||||
// might generate an exception while attempting
|
||||
// to fetch the next batch to determine
|
||||
// whether there are any more elements
|
||||
|
||||
// test if the current set of entries has been processed
|
||||
if (posn == limit) {
|
||||
getNextBatch();
|
||||
}
|
||||
|
||||
// test if any unprocessed entries exist
|
||||
if (posn < limit) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
try {
|
||||
// try to process another referral
|
||||
return hasMoreReferrals();
|
||||
|
||||
} catch (LdapReferralException |
|
||||
LimitExceededException |
|
||||
PartialResultException e) {
|
||||
cleanup();
|
||||
throw e;
|
||||
|
||||
} catch (NamingException e) {
|
||||
cleanup();
|
||||
PartialResultException pre = new PartialResultException();
|
||||
pre.setRootCause(e);
|
||||
throw pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the next entry.
|
||||
*/
|
||||
private T nextImpl() throws NamingException {
|
||||
try {
|
||||
return nextAux();
|
||||
} catch (NamingException e) {
|
||||
cleanup();
|
||||
throw cont.fillInException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private T nextAux() throws NamingException {
|
||||
if (posn == limit) {
|
||||
getNextBatch(); // updates posn and limit
|
||||
}
|
||||
|
||||
if (posn >= limit) {
|
||||
cleanup();
|
||||
throw new NoSuchElementException("invalid enumeration handle");
|
||||
}
|
||||
|
||||
LdapEntry result = entries.elementAt(posn++);
|
||||
|
||||
// gets and outputs DN from the entry
|
||||
return createItem(result.DN, result.attributes, result.respCtls);
|
||||
}
|
||||
|
||||
protected final String getAtom(String dn) {
|
||||
// need to strip off all but lowest component of dn
|
||||
// so that is relative to current context (currentDN)
|
||||
try {
|
||||
Name parsed = new LdapName(dn);
|
||||
return parsed.get(parsed.size() - 1);
|
||||
} catch (NamingException e) {
|
||||
return dn;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls) throws NamingException;
|
||||
|
||||
/*
|
||||
* Append the supplied (chain of) referrals onto the
|
||||
* end of the current (chain of) referrals.
|
||||
*/
|
||||
@Override
|
||||
public void appendUnprocessedReferrals(LdapReferralException ex) {
|
||||
if (refEx != null) {
|
||||
refEx = refEx.appendUnprocessedReferrals(ex);
|
||||
} else {
|
||||
refEx = ex.appendUnprocessedReferrals(refEx);
|
||||
}
|
||||
}
|
||||
|
||||
final void setNamingException(NamingException e) {
|
||||
errEx = e;
|
||||
}
|
||||
|
||||
protected abstract AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException;
|
||||
|
||||
/*
|
||||
* Iterate through the URLs of a referral. If successful then perform
|
||||
* a search operation and merge the received results with the current
|
||||
* results.
|
||||
*/
|
||||
protected final boolean hasMoreReferrals() throws NamingException {
|
||||
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
|
||||
if (homeCtx.handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw (NamingException)(refEx.fillInStackTrace());
|
||||
}
|
||||
|
||||
// process the referrals sequentially
|
||||
while (true) {
|
||||
|
||||
LdapReferralContext refCtx =
|
||||
(LdapReferralContext)refEx.getReferralContext(
|
||||
homeCtx.envprops, homeCtx.reqCtls);
|
||||
|
||||
try {
|
||||
|
||||
update(getReferredResults(refCtx));
|
||||
break;
|
||||
|
||||
} catch (LdapReferralException re) {
|
||||
|
||||
// record a previous exception
|
||||
if (errEx == null) {
|
||||
errEx = re.getNamingException();
|
||||
}
|
||||
refEx = re;
|
||||
continue;
|
||||
|
||||
} finally {
|
||||
// Make sure we close referral context
|
||||
refCtx.close();
|
||||
}
|
||||
}
|
||||
return hasMoreImpl();
|
||||
|
||||
} else {
|
||||
cleanup();
|
||||
|
||||
if (errEx != null) {
|
||||
throw errEx;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge the entries and/or referrals from the supplied enumeration
|
||||
* with those of the current enumeration.
|
||||
*/
|
||||
protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
|
||||
// Cleanup previous context first
|
||||
homeCtx.decEnumCount();
|
||||
|
||||
// New enum will have already incremented enum count and recorded clnt
|
||||
homeCtx = ne.homeCtx;
|
||||
enumClnt = ne.enumClnt;
|
||||
|
||||
// Do this to prevent referral enumeration (ne) from decrementing
|
||||
// enum count because we'll be doing that here from this
|
||||
// enumeration.
|
||||
ne.homeCtx = null;
|
||||
|
||||
// Record rest of information from new enum
|
||||
posn = ne.posn;
|
||||
limit = ne.limit;
|
||||
res = ne.res;
|
||||
entries = ne.entries;
|
||||
refEx = ne.refEx;
|
||||
listArg = ne.listArg;
|
||||
}
|
||||
|
||||
protected final void finalize() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
protected final void cleanup() {
|
||||
if (cleaned) return; // been there; done that
|
||||
|
||||
if(enumClnt != null) {
|
||||
enumClnt.clearSearchReply(res, homeCtx.reqCtls);
|
||||
}
|
||||
|
||||
enumClnt = null;
|
||||
cleaned = true;
|
||||
if (homeCtx != null) {
|
||||
homeCtx.decEnumCount();
|
||||
homeCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void close() {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
118
jdkSrc/jdk8/com/sun/jndi/ldap/BasicControl.java
Normal file
118
jdkSrc/jdk8/com/sun/jndi/ldap/BasicControl.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
/**
|
||||
* This class provides a basic implementation of the <tt>Control</tt>
|
||||
* interface. It represents an LDAPv3 Control as defined in RFC-2251.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public class BasicControl implements Control {
|
||||
|
||||
/**
|
||||
* The control's object identifier string.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected String id;
|
||||
|
||||
/**
|
||||
* The control's criticality.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected boolean criticality = false; // default
|
||||
|
||||
/**
|
||||
* The control's ASN.1 BER encoded value.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected byte[] value = null;
|
||||
|
||||
private static final long serialVersionUID = -5914033725246428413L;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of BasicControl.
|
||||
* It is a non-critical control.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
*
|
||||
*/
|
||||
public BasicControl(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of BasicControl.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
* @param criticality The control's criticality.
|
||||
* @param value The control's ASN.1 BER encoded value.
|
||||
* May be null.
|
||||
*/
|
||||
public BasicControl(String id, boolean criticality, byte[] value) {
|
||||
this.id = id;
|
||||
this.criticality = criticality;
|
||||
if (value != null) {
|
||||
this.value = value.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the control's object identifier string.
|
||||
*
|
||||
* @return The non-null object identifier string.
|
||||
*/
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the control's criticality.
|
||||
*
|
||||
* @return true if the control is critical; false otherwise.
|
||||
*/
|
||||
public boolean isCritical() {
|
||||
return criticality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the control's ASN.1 BER encoded value.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the control's value. It does not include the control's object
|
||||
* identifier string or criticality.
|
||||
*
|
||||
* @return A possibly null byte array representing the control's
|
||||
* ASN.1 BER encoded value.
|
||||
*/
|
||||
public byte[] getEncodedValue() {
|
||||
return value == null ? null : value.clone();
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/jndi/ldap/Ber.java
Normal file
109
jdkSrc/jdk8/com/sun/jndi/ldap/Ber.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import sun.misc.HexDumpEncoder;
|
||||
|
||||
/**
|
||||
* Base class that defines common fields, constants, and debug method.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
*/
|
||||
public abstract class Ber {
|
||||
|
||||
protected byte buf[];
|
||||
protected int offset;
|
||||
protected int bufsize;
|
||||
|
||||
protected Ber() {
|
||||
}
|
||||
|
||||
public static void dumpBER(OutputStream outStream, String tag, byte[] bytes,
|
||||
int from, int to) {
|
||||
|
||||
try {
|
||||
outStream.write('\n');
|
||||
outStream.write(tag.getBytes("UTF8"));
|
||||
|
||||
new HexDumpEncoder().encodeBuffer(
|
||||
new ByteArrayInputStream(bytes, from, to),
|
||||
outStream);
|
||||
|
||||
outStream.write('\n');
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
outStream.write(
|
||||
"Ber.dumpBER(): error encountered\n".getBytes("UTF8"));
|
||||
} catch (IOException e2) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// some ASN defines
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static final int ASN_BOOLEAN = 0x01;
|
||||
public static final int ASN_INTEGER = 0x02;
|
||||
public static final int ASN_BIT_STRING = 0x03;
|
||||
public static final int ASN_SIMPLE_STRING = 0x04;
|
||||
public static final int ASN_OCTET_STR = 0x04;
|
||||
public static final int ASN_NULL = 0x05;
|
||||
public static final int ASN_OBJECT_ID = 0x06;
|
||||
public static final int ASN_SEQUENCE = 0x10;
|
||||
public static final int ASN_SET = 0x11;
|
||||
|
||||
|
||||
public static final int ASN_PRIMITIVE = 0x00;
|
||||
public static final int ASN_UNIVERSAL = 0x00;
|
||||
public static final int ASN_CONSTRUCTOR = 0x20;
|
||||
public static final int ASN_APPLICATION = 0x40;
|
||||
public static final int ASN_CONTEXT = 0x80;
|
||||
public static final int ASN_PRIVATE = 0xC0;
|
||||
|
||||
public static final int ASN_ENUMERATED = 0x0a;
|
||||
|
||||
final static class EncodeException extends IOException {
|
||||
private static final long serialVersionUID = -5247359637775781768L;
|
||||
EncodeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
final static class DecodeException extends IOException {
|
||||
private static final long serialVersionUID = 8735036969244425583L;
|
||||
DecodeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
341
jdkSrc/jdk8/com/sun/jndi/ldap/BerDecoder.java
Normal file
341
jdkSrc/jdk8/com/sun/jndi/ldap/BerDecoder.java
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A BER decoder. Contains methods to parse a BER buffer.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public final class BerDecoder extends Ber {
|
||||
|
||||
private int origOffset; // The start point in buf to decode
|
||||
|
||||
/**
|
||||
* Creates a BER decoder that reads bytes from the specified buffer.
|
||||
*/
|
||||
public BerDecoder(byte buf[], int offset, int bufsize) {
|
||||
|
||||
this.buf = buf; // shared buffer, be careful to use this class
|
||||
this.bufsize = bufsize;
|
||||
this.origOffset = offset;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this decode to start parsing from the initial offset
|
||||
* (ie., same state as after calling the constructor).
|
||||
*/
|
||||
public void reset() {
|
||||
offset = origOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current parse position.
|
||||
* It points to the byte that will be parsed next.
|
||||
* Useful for parsing sequences.
|
||||
*/
|
||||
public int getParsePosition() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a possibly variable length field.
|
||||
*/
|
||||
public int parseLength() throws DecodeException {
|
||||
|
||||
int lengthbyte = parseByte();
|
||||
|
||||
if ((lengthbyte & 0x80) == 0x80) {
|
||||
|
||||
lengthbyte &= 0x7f;
|
||||
|
||||
if (lengthbyte == 0) {
|
||||
throw new DecodeException(
|
||||
"Indefinite length not supported");
|
||||
}
|
||||
|
||||
if (lengthbyte > 4) {
|
||||
throw new DecodeException("encoding too long");
|
||||
}
|
||||
|
||||
if (bufsize - offset < lengthbyte) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
int retval = 0;
|
||||
|
||||
for( int i = 0; i < lengthbyte; i++) {
|
||||
retval = (retval << 8) + (buf[offset++] & 0xff);
|
||||
}
|
||||
if (retval < 0) {
|
||||
throw new DecodeException("Invalid length bytes");
|
||||
}
|
||||
return retval;
|
||||
} else {
|
||||
return lengthbyte;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next sequence in this BER buffer.
|
||||
* @param rlen An array for returning size of the sequence in bytes. If null,
|
||||
* the size is not returned.
|
||||
* @return The sequence's tag.
|
||||
*/
|
||||
public int parseSeq(int rlen[]) throws DecodeException {
|
||||
|
||||
int seq = parseByte();
|
||||
int len = parseLength();
|
||||
if (rlen != null) {
|
||||
rlen[0] = len;
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to skip bytes. Usually used when trying to recover from parse error.
|
||||
* Don't need to be public right now?
|
||||
* @param i The number of bytes to skip
|
||||
*/
|
||||
void seek(int i) throws DecodeException {
|
||||
if (offset + i > bufsize || offset + i < 0) {
|
||||
throw new DecodeException("array index out of bounds");
|
||||
}
|
||||
offset += i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next byte in this BER buffer.
|
||||
* @return The byte parsed.
|
||||
*/
|
||||
public int parseByte() throws DecodeException {
|
||||
if (bufsize - offset < 1) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
return buf[offset++] & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next byte in this BER buffer without consuming it.
|
||||
* @return The next byte.
|
||||
*/
|
||||
public int peekByte() throws DecodeException {
|
||||
if (bufsize - offset < 1) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
return buf[offset] & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_BOOLEAN tagged integer from this BER buffer.
|
||||
* @return true if the tagged integer is 0; false otherwise.
|
||||
*/
|
||||
public boolean parseBoolean() throws DecodeException {
|
||||
return ((parseIntWithTag(ASN_BOOLEAN) == 0x00) ? false : true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_ENUMERATED tagged integer from this BER buffer.
|
||||
* @return The tag of enumeration.
|
||||
*/
|
||||
public int parseEnumeration() throws DecodeException {
|
||||
return parseIntWithTag(ASN_ENUMERATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN_INTEGER tagged integer from this BER buffer.
|
||||
* @return The value of the integer.
|
||||
*/
|
||||
public int parseInt() throws DecodeException {
|
||||
return parseIntWithTag(ASN_INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an integer that's preceded by a tag.
|
||||
*<blockquote><pre>
|
||||
* BER integer ::= tag length byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
private int parseIntWithTag(int tag) throws DecodeException {
|
||||
if (parseByte() != tag) {
|
||||
// Ber could have been reset;
|
||||
String s;
|
||||
if (offset > 0) {
|
||||
s = Integer.toString(buf[offset - 1] & 0xff);
|
||||
} else {
|
||||
s = "Empty tag";
|
||||
}
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
s + " (expected tag " + Integer.toString(tag) + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > 4) {
|
||||
throw new DecodeException("INTEGER too long");
|
||||
} else if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
byte fb = buf[offset++];
|
||||
int value = 0;
|
||||
|
||||
value = fb & 0x7F;
|
||||
for( int i = 1 /* first byte already read */ ; i < len; i++) {
|
||||
value <<= 8;
|
||||
value |= (buf[offset++] & 0xff);
|
||||
}
|
||||
|
||||
if ((fb & 0x80) == 0x80) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string.
|
||||
*/
|
||||
public String parseString(boolean decodeUTF8) throws DecodeException {
|
||||
return parseStringWithTag(ASN_SIMPLE_STRING, decodeUTF8, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string of a given tag from this BER buffer.
|
||||
*<blockquote><pre>
|
||||
*BER simple string ::= tag length {byte}*
|
||||
*</pre></blockquote>
|
||||
* @param rlen An array for holding the relative parsed offset; if null
|
||||
* offset not set.
|
||||
* @param decodeUTF8 If true, use UTF-8 when decoding the string; otherwise
|
||||
* use ISO-Latin-1 (8859_1). Use true for LDAPv3; false for LDAPv2.
|
||||
* @param tag The tag that precedes the string.
|
||||
* @return The non-null parsed string.
|
||||
*/
|
||||
public String parseStringWithTag(int tag, boolean decodeUTF8, int rlen[])
|
||||
throws DecodeException {
|
||||
|
||||
int st;
|
||||
int origOffset = offset;
|
||||
|
||||
if ((st = parseByte()) != tag) {
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
Integer.toString((byte)st) + " (expected tag " + tag + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
String retstr;
|
||||
if (len == 0) {
|
||||
retstr = "";
|
||||
} else {
|
||||
byte[] buf2 = new byte[len];
|
||||
|
||||
System.arraycopy(buf, offset, buf2, 0, len);
|
||||
if (decodeUTF8) {
|
||||
try {
|
||||
retstr = new String(buf2, "UTF8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new DecodeException("UTF8 not available on platform");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
retstr = new String(buf2, "8859_1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new DecodeException("8859_1 not available on platform");
|
||||
}
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (rlen != null) {
|
||||
rlen[0] = offset - origOffset;
|
||||
}
|
||||
|
||||
return retstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an octet string of a given type(tag) from this BER buffer.
|
||||
* <blockquote><pre>
|
||||
* BER Binary Data of type "tag" ::= tag length {byte}*
|
||||
*</pre></blockquote>
|
||||
*
|
||||
* @param tag The tag to look for.
|
||||
* @param rlen An array for returning the relative parsed position. If null,
|
||||
* the relative parsed position is not returned.
|
||||
* @return A non-null array containing the octet string.
|
||||
* @throws DecodeException If the next byte in the BER buffer is not
|
||||
* <tt>tag</tt>, or if length specified in the BER buffer exceeds the
|
||||
* number of bytes left in the buffer.
|
||||
*/
|
||||
public byte[] parseOctetString(int tag, int rlen[]) throws DecodeException {
|
||||
|
||||
int origOffset = offset;
|
||||
int st;
|
||||
if ((st = parseByte()) != tag) {
|
||||
|
||||
throw new DecodeException("Encountered ASN.1 tag " +
|
||||
Integer.toString(st) +
|
||||
" (expected tag " + Integer.toString(tag) + ")");
|
||||
}
|
||||
|
||||
int len = parseLength();
|
||||
|
||||
if (len > bufsize - offset) {
|
||||
throw new DecodeException("Insufficient data");
|
||||
}
|
||||
|
||||
byte retarr[] = new byte[len];
|
||||
if (len > 0) {
|
||||
System.arraycopy(buf, offset, retarr, 0, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if (rlen != null) {
|
||||
rlen[0] = offset - origOffset;
|
||||
}
|
||||
|
||||
return retarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of unparsed bytes in this BER buffer.
|
||||
*/
|
||||
public int bytesLeft() {
|
||||
return bufsize - offset;
|
||||
}
|
||||
}
|
||||
429
jdkSrc/jdk8/com/sun/jndi/ldap/BerEncoder.java
Normal file
429
jdkSrc/jdk8/com/sun/jndi/ldap/BerEncoder.java
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A BER encoder.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Scott Seligman
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public final class BerEncoder extends Ber {
|
||||
|
||||
private int curSeqIndex;
|
||||
private int seqOffset[];
|
||||
private static final int INITIAL_SEQUENCES = 16;
|
||||
private static final int DEFAULT_BUFSIZE = 1024;
|
||||
|
||||
// When buf is full, expand its size by the following factor.
|
||||
private static final int BUF_GROWTH_FACTOR = 8;
|
||||
|
||||
/**
|
||||
* Creates a BER buffer for encoding.
|
||||
*/
|
||||
public BerEncoder() {
|
||||
this(DEFAULT_BUFSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a BER buffer of a specified size for encoding.
|
||||
* Specify the initial bufsize. Buffer will be expanded as needed.
|
||||
* @param bufsize The number of bytes for the buffer.
|
||||
*/
|
||||
public BerEncoder(int bufsize) {
|
||||
buf = new byte[bufsize];
|
||||
this.bufsize = bufsize;
|
||||
offset = 0;
|
||||
|
||||
seqOffset = new int[INITIAL_SEQUENCES];
|
||||
curSeqIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets encoder to state when newly constructed. Zeros out
|
||||
* internal data structures.
|
||||
*/
|
||||
public void reset() {
|
||||
while (offset > 0) {
|
||||
buf[--offset] = 0;
|
||||
}
|
||||
while (curSeqIndex > 0) {
|
||||
seqOffset[--curSeqIndex] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ Accessor methods ------------
|
||||
|
||||
/**
|
||||
* Gets the number of encoded bytes in this BER buffer.
|
||||
*/
|
||||
public int getDataLen() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer that contains the BER encoding. Throws an
|
||||
* exception if unmatched beginSeq() and endSeq() pairs were
|
||||
* encountered. Not entire buffer contains encoded bytes.
|
||||
* Use getDataLen() to determine number of encoded bytes.
|
||||
* Use getBuffer(true) to get rid of excess bytes in array.
|
||||
* @throws IllegalStateException If buffer contains unbalanced sequence.
|
||||
*/
|
||||
public byte[] getBuf() {
|
||||
if (curSeqIndex != 0) {
|
||||
throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
|
||||
}
|
||||
return buf; // shared buffer, be careful to use this method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer that contains the BER encoding, trimming unused bytes.
|
||||
*
|
||||
* @throws IllegalStateException If buffer contains unbalanced sequence.
|
||||
*/
|
||||
public byte[] getTrimmedBuf() {
|
||||
int len = getDataLen();
|
||||
byte[] trimBuf = new byte[len];
|
||||
|
||||
System.arraycopy(getBuf(), 0, trimBuf, 0, len);
|
||||
return trimBuf;
|
||||
}
|
||||
|
||||
// -------------- encoding methods -------------
|
||||
|
||||
/**
|
||||
* Begin encoding a sequence with a tag.
|
||||
*/
|
||||
public void beginSeq(int tag) {
|
||||
|
||||
// Double the size of the SEQUENCE array if it overflows
|
||||
if (curSeqIndex >= seqOffset.length) {
|
||||
int[] seqOffsetTmp = new int[seqOffset.length * 2];
|
||||
|
||||
for (int i = 0; i < seqOffset.length; i++) {
|
||||
seqOffsetTmp[i] = seqOffset[i];
|
||||
}
|
||||
seqOffset = seqOffsetTmp;
|
||||
}
|
||||
|
||||
encodeByte(tag);
|
||||
seqOffset[curSeqIndex] = offset;
|
||||
|
||||
// Save space for sequence length.
|
||||
// %%% Currently we save enough space for sequences up to 64k.
|
||||
// For larger sequences we'll need to shift the data to the right
|
||||
// in endSeq(). If we could instead pad the length field with
|
||||
// zeros, it would be a big win.
|
||||
ensureFreeBytes(3);
|
||||
offset += 3;
|
||||
|
||||
curSeqIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate a BER sequence.
|
||||
*/
|
||||
public void endSeq() throws EncodeException {
|
||||
curSeqIndex--;
|
||||
if (curSeqIndex < 0) {
|
||||
throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs.");
|
||||
}
|
||||
|
||||
int start = seqOffset[curSeqIndex] + 3; // index beyond length field
|
||||
int len = offset - start;
|
||||
|
||||
if (len <= 0x7f) {
|
||||
shiftSeqData(start, len, -2);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) len;
|
||||
} else if (len <= 0xff) {
|
||||
shiftSeqData(start, len, -1);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x81;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) len;
|
||||
} else if (len <= 0xffff) {
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x82;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 8);
|
||||
buf[seqOffset[curSeqIndex] + 2] = (byte) len;
|
||||
} else if (len <= 0xffffff) {
|
||||
shiftSeqData(start, len, 1);
|
||||
buf[seqOffset[curSeqIndex]] = (byte) 0x83;
|
||||
buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 16);
|
||||
buf[seqOffset[curSeqIndex] + 2] = (byte) (len >> 8);
|
||||
buf[seqOffset[curSeqIndex] + 3] = (byte) len;
|
||||
} else {
|
||||
throw new EncodeException("SEQUENCE too long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts contents of buf in the range [start,start+len) a specified amount.
|
||||
* Positive shift value means shift to the right.
|
||||
*/
|
||||
private void shiftSeqData(int start, int len, int shift) {
|
||||
if (shift > 0) {
|
||||
ensureFreeBytes(shift);
|
||||
}
|
||||
System.arraycopy(buf, start, buf, start + shift, len);
|
||||
offset += shift;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a single byte.
|
||||
*/
|
||||
public void encodeByte(int b) {
|
||||
ensureFreeBytes(1);
|
||||
buf[offset++] = (byte) b;
|
||||
}
|
||||
|
||||
/*
|
||||
private void deleteByte() {
|
||||
offset--;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Encodes an int.
|
||||
*<blockquote><pre>
|
||||
* BER integer ::= 0x02 berlength byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeInt(int i) {
|
||||
encodeInt(i, 0x02);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an int and a tag.
|
||||
*<blockquote><pre>
|
||||
* BER integer w tag ::= tag berlength byte {byte}*
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeInt(int i, int tag) {
|
||||
int mask = 0xff800000;
|
||||
int intsize = 4;
|
||||
|
||||
while( (((i & mask) == 0) || ((i & mask) == mask)) && (intsize > 1) ) {
|
||||
intsize--;
|
||||
i <<= 8;
|
||||
}
|
||||
|
||||
encodeInt(i, tag, intsize);
|
||||
}
|
||||
|
||||
//
|
||||
// encodes an int using numbytes for the actual encoding.
|
||||
//
|
||||
private void encodeInt(int i, int tag, int intsize) {
|
||||
|
||||
//
|
||||
// integer ::= 0x02 asnlength byte {byte}*
|
||||
//
|
||||
|
||||
if (intsize > 4) {
|
||||
throw new IllegalArgumentException("BER encode error: INTEGER too long.");
|
||||
}
|
||||
|
||||
ensureFreeBytes(2 + intsize);
|
||||
|
||||
buf[offset++] = (byte) tag;
|
||||
buf[offset++] = (byte) intsize;
|
||||
|
||||
int mask = 0xff000000;
|
||||
|
||||
while (intsize-- > 0) {
|
||||
buf[offset++] = (byte) ((i & mask) >> 24);
|
||||
i <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a boolean.
|
||||
*<blockquote><pre>
|
||||
* BER boolean ::= 0x01 0x01 {0xff|0x00}
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeBoolean(boolean b) {
|
||||
encodeBoolean(b, ASN_BOOLEAN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a boolean and a tag
|
||||
*<blockquote><pre>
|
||||
* BER boolean w TAG ::= tag 0x01 {0xff|0x00}
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeBoolean(boolean b, int tag) {
|
||||
ensureFreeBytes(3);
|
||||
|
||||
buf[offset++] = (byte) tag;
|
||||
buf[offset++] = 0x01;
|
||||
buf[offset++] = b ? (byte) 0xff : (byte) 0x00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string.
|
||||
*<blockquote><pre>
|
||||
* BER string ::= 0x04 strlen byte1 byte2...
|
||||
*</pre></blockquote>
|
||||
* The string is converted into bytes using UTF-8 or ISO-Latin-1.
|
||||
*/
|
||||
public void encodeString(String str, boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
encodeString(str, ASN_OCTET_STR, encodeUTF8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string and a tag.
|
||||
*<blockquote><pre>
|
||||
* BER string w TAG ::= tag strlen byte1 byte2...
|
||||
*</pre></blockquote>
|
||||
*/
|
||||
public void encodeString(String str, int tag, boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
|
||||
encodeByte(tag);
|
||||
|
||||
int i = 0;
|
||||
int count;
|
||||
byte[] bytes = null;
|
||||
|
||||
if (str == null) {
|
||||
count = 0;
|
||||
} else if (encodeUTF8) {
|
||||
try {
|
||||
bytes = str.getBytes("UTF8");
|
||||
count = bytes.length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new EncodeException("UTF8 not available on platform");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
bytes = str.getBytes("8859_1");
|
||||
count = bytes.length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new EncodeException("8859_1 not available on platform");
|
||||
}
|
||||
}
|
||||
|
||||
encodeLength(count);
|
||||
|
||||
ensureFreeBytes(count);
|
||||
while (i < count) {
|
||||
buf[offset++] = bytes[i++];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a portion of an octet string and a tag.
|
||||
*/
|
||||
public void encodeOctetString(byte tb[], int tag, int tboffset, int length)
|
||||
throws EncodeException {
|
||||
|
||||
encodeByte(tag);
|
||||
encodeLength(length);
|
||||
|
||||
if (length > 0) {
|
||||
ensureFreeBytes(length);
|
||||
System.arraycopy(tb, tboffset, buf, offset, length);
|
||||
offset += length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an octet string and a tag.
|
||||
*/
|
||||
public void encodeOctetString(byte tb[], int tag) throws EncodeException {
|
||||
encodeOctetString(tb, tag, 0, tb.length);
|
||||
}
|
||||
|
||||
private void encodeLength(int len) throws EncodeException {
|
||||
ensureFreeBytes(4); // worst case
|
||||
|
||||
if (len < 128) {
|
||||
buf[offset++] = (byte) len;
|
||||
} else if (len <= 0xff) {
|
||||
buf[offset++] = (byte) 0x81;
|
||||
buf[offset++] = (byte) len;
|
||||
} else if (len <= 0xffff) {
|
||||
buf[offset++] = (byte) 0x82;
|
||||
buf[offset++] = (byte) (len >> 8);
|
||||
buf[offset++] = (byte) (len & 0xff);
|
||||
} else if (len <= 0xffffff) {
|
||||
buf[offset++] = (byte) 0x83;
|
||||
buf[offset++] = (byte) (len >> 16);
|
||||
buf[offset++] = (byte) (len >> 8);
|
||||
buf[offset++] = (byte) (len & 0xff);
|
||||
} else {
|
||||
throw new EncodeException("string too long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an array of strings.
|
||||
*/
|
||||
public void encodeStringArray(String strs[], boolean encodeUTF8)
|
||||
throws EncodeException {
|
||||
if (strs == null)
|
||||
return;
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
encodeString(strs[i], encodeUTF8);
|
||||
}
|
||||
}
|
||||
/*
|
||||
private void encodeNull() {
|
||||
|
||||
//
|
||||
// NULL ::= 0x05 0x00
|
||||
//
|
||||
encodeByte(0x05);
|
||||
encodeByte(0x00);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensures that there are at least "len" unused bytes in "buf".
|
||||
* When more space is needed "buf" is expanded by a factor of
|
||||
* BUF_GROWTH_FACTOR, then "len" bytes are added if "buf" still
|
||||
* isn't large enough.
|
||||
*/
|
||||
private void ensureFreeBytes(int len) {
|
||||
if (bufsize - offset < len) {
|
||||
int newsize = bufsize * BUF_GROWTH_FACTOR;
|
||||
if (newsize - offset < len) {
|
||||
newsize += len;
|
||||
}
|
||||
byte newbuf[] = new byte[newsize];
|
||||
// Only copy bytes in the range [0, offset)
|
||||
System.arraycopy(buf, 0, newbuf, 0, offset);
|
||||
|
||||
buf = newbuf;
|
||||
bufsize = newsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/com/sun/jndi/ldap/BindingWithControls.java
Normal file
44
jdkSrc/jdk8/com/sun/jndi/ldap/BindingWithControls.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class BindingWithControls extends Binding implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public BindingWithControls(String name, Object obj, Control[] controls) {
|
||||
super(name, obj);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 9117274533692320040L;
|
||||
}
|
||||
227
jdkSrc/jdk8/com/sun/jndi/ldap/ClientId.java
Normal file
227
jdkSrc/jdk8/com/sun/jndi/ldap/ClientId.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Arrays; // JDK 1.2
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
/**
|
||||
* Represents identity information about an anonymous LDAP connection.
|
||||
* This base class contains the following information:
|
||||
* - protocol version number
|
||||
* - server's hostname (case-insensitive)
|
||||
* - server's port number
|
||||
* - prototype type (plain or ssl)
|
||||
* - controls to be sent with the LDAP bind request
|
||||
*
|
||||
* All other identity classes must be a subclass of ClientId.
|
||||
* Identity subclasses would add more distinguishing information, depending
|
||||
* on the type of authentication that the connection is to have.
|
||||
*
|
||||
* The equals() and hashCode() methods of this class and its subclasses are
|
||||
* important because they are used to determine whether two requests for
|
||||
* the same connection are identical, and thus whether the same connection
|
||||
* may be shared. This is especially important for authenticated connections
|
||||
* because a mistake would result in a serious security violation.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class ClientId {
|
||||
final private int version;
|
||||
final private String hostname;
|
||||
final private int port;
|
||||
final private String protocol;
|
||||
final private Control[] bindCtls;
|
||||
final private OutputStream trace;
|
||||
final private String socketFactory;
|
||||
final private int myHash;
|
||||
final private int ctlHash;
|
||||
|
||||
private SocketFactory factory = null;
|
||||
private Method sockComparator = null;
|
||||
private boolean isDefaultSockFactory = false;
|
||||
final public static boolean debug = false;
|
||||
|
||||
ClientId(int version, String hostname, int port, String protocol,
|
||||
Control[] bindCtls, OutputStream trace, String socketFactory) {
|
||||
this.version = version;
|
||||
this.hostname = hostname.toLowerCase(Locale.ENGLISH); // ignore case
|
||||
this.port = port;
|
||||
this.protocol = protocol;
|
||||
this.bindCtls = (bindCtls != null ? bindCtls.clone() : null);
|
||||
this.trace = trace;
|
||||
//
|
||||
// Needed for custom socket factory pooling
|
||||
//
|
||||
this.socketFactory = socketFactory;
|
||||
if ((socketFactory != null) &&
|
||||
!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {
|
||||
try {
|
||||
Class<?> socketFactoryClass =
|
||||
Obj.helper.loadClass(socketFactory);
|
||||
Class<?> objClass = Class.forName("java.lang.Object");
|
||||
this.sockComparator = socketFactoryClass.getMethod(
|
||||
"compare", new Class<?>[]{objClass, objClass});
|
||||
Method getDefault = socketFactoryClass.getMethod(
|
||||
"getDefault", new Class<?>[]{});
|
||||
this.factory =
|
||||
(SocketFactory)getDefault.invoke(null, new Object[]{});
|
||||
} catch (Exception e) {
|
||||
// Ignore it here, the same exceptions are/will be handled by
|
||||
// LdapPoolManager and Connection classes.
|
||||
if (debug) {
|
||||
System.out.println("ClientId received an exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isDefaultSockFactory = true;
|
||||
}
|
||||
|
||||
// The SocketFactory field is not used in the myHash
|
||||
// computation as there is no right way to compute the hash code
|
||||
// for this field. There is no harm in skipping it from the hash
|
||||
// computation
|
||||
myHash = version + port
|
||||
+ (trace != null ? trace.hashCode() : 0)
|
||||
+ (this.hostname != null ? this.hostname.hashCode() : 0)
|
||||
+ (protocol != null ? protocol.hashCode() : 0)
|
||||
+ (ctlHash=hashCodeControls(bindCtls));
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ClientId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClientId other = (ClientId)obj;
|
||||
|
||||
return myHash == other.myHash
|
||||
&& version == other.version
|
||||
&& port == other.port
|
||||
&& trace == other.trace
|
||||
&& (hostname == other.hostname // null OK
|
||||
|| (hostname != null && hostname.equals(other.hostname)))
|
||||
&& (protocol == other.protocol // null OK
|
||||
|| (protocol != null && protocol.equals(other.protocol)))
|
||||
&& ctlHash == other.ctlHash
|
||||
&& (equalsControls(bindCtls, other.bindCtls))
|
||||
&& (equalsSockFactory(other));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
private static int hashCodeControls(Control[] c) {
|
||||
if (c == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int code = 0;
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
code = code * 31 + c[i].getID().hashCode();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private static boolean equalsControls(Control[] a, Control[] b) {
|
||||
if (a == b) {
|
||||
return true; // both null or same
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false; // one is non-null
|
||||
}
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (!a[i].getID().equals(b[i].getID())
|
||||
|| a[i].isCritical() != b[i].isCritical()
|
||||
|| !Arrays.equals(a[i].getEncodedValue(),
|
||||
b[i].getEncodedValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean equalsSockFactory(ClientId other) {
|
||||
if (this.isDefaultSockFactory && other.isDefaultSockFactory) {
|
||||
return true;
|
||||
}
|
||||
else if (!other.isDefaultSockFactory) {
|
||||
return invokeComparator(other, this);
|
||||
} else {
|
||||
return invokeComparator(this, other);
|
||||
}
|
||||
}
|
||||
|
||||
// delegate the comparison work to the SocketFactory class
|
||||
// as there is no enough information here, to do the comparison
|
||||
private boolean invokeComparator(ClientId c1, ClientId c2) {
|
||||
Object ret;
|
||||
try {
|
||||
ret = (c1.sockComparator).invoke(
|
||||
c1.factory, c1.socketFactory, c2.socketFactory);
|
||||
} catch(Exception e) {
|
||||
if (debug) {
|
||||
System.out.println("ClientId received an exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Failed to invoke the comparator; flag unequality
|
||||
return false;
|
||||
}
|
||||
if (((Integer) ret) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String toStringControls(Control[] ctls) {
|
||||
if (ctls == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer str = new StringBuffer();
|
||||
for (int i = 0; i < ctls.length; i++) {
|
||||
str.append(ctls[i].getID());
|
||||
str.append(' ');
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (hostname + ":" + port + ":" +
|
||||
(protocol != null ? protocol : "") + ":" +
|
||||
toStringControls(bindCtls) + ":" +
|
||||
socketFactory);
|
||||
}
|
||||
}
|
||||
1046
jdkSrc/jdk8/com/sun/jndi/ldap/Connection.java
Normal file
1046
jdkSrc/jdk8/com/sun/jndi/ldap/Connection.java
Normal file
File diff suppressed because it is too large
Load Diff
86
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultLdapDnsProvider.java
Normal file
86
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultLdapDnsProvider.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, 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.ldap;
|
||||
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProvider;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DefaultLdapDnsProvider {
|
||||
|
||||
public Optional<LdapDnsProviderResult> lookupEndpoints(String url,
|
||||
Map<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
if (url == null || env == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
String domainName;
|
||||
List<String> endpoints = new ArrayList<>();
|
||||
LdapURL ldapUrl = new LdapURL(url);
|
||||
String dn = ldapUrl.getDN();
|
||||
String host = ldapUrl.getHost();
|
||||
int port = ldapUrl.getPort();
|
||||
String[] hostports;
|
||||
|
||||
// handle a URL with no hostport (ldap:/// or ldaps:///)
|
||||
// locate the LDAP service using the URL's distinguished name
|
||||
if (host == null
|
||||
&& port == -1
|
||||
&& dn != null
|
||||
&& (domainName = ServiceLocator.mapDnToDomainName(dn)) != null
|
||||
&& (hostports = ServiceLocator.getLdapService(domainName, env)) != null) {
|
||||
// Generate new URLs that include the discovered hostports.
|
||||
// Reuse the original URL scheme.
|
||||
String scheme = ldapUrl.getScheme() + "://";
|
||||
String query = ldapUrl.getQuery();
|
||||
String urlSuffix = ldapUrl.getPath() + (query != null ? query : "");
|
||||
for (String hostPort : hostports) {
|
||||
// the hostports come from the DNS SRV records
|
||||
// we assume the SRV record is scheme aware
|
||||
endpoints.add(scheme + hostPort + urlSuffix);
|
||||
}
|
||||
} else {
|
||||
// we don't have enough information to set the domain name
|
||||
// correctly
|
||||
domainName = "";
|
||||
endpoints.add(url);
|
||||
}
|
||||
|
||||
LdapDnsProviderResult res = new LdapDnsProviderResult(domainName, endpoints);
|
||||
if (res.getEndpoints().isEmpty() && res.getDomainName().isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(res);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
100
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultResponseControlFactory.java
Normal file
100
jdkSrc/jdk8/com/sun/jndi/ldap/DefaultResponseControlFactory.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2003, 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
/**
|
||||
* This class represents a factory for creating LDAPv3 response controls.
|
||||
* The following response controls are supported:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Paged results, as defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>.
|
||||
* <li>
|
||||
* Server-side sorting, as defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2891.txt">RFC 2891</a>.
|
||||
* <li>
|
||||
* Entry change response control, as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
* </ul>
|
||||
*
|
||||
* @see javax.naming.ldap.SortResponseControl
|
||||
* @see javax.naming.ldap.PagedResultsResponseControl
|
||||
* @see PersistentSearchControl
|
||||
* @see EntryChangeResponseControl
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public class DefaultResponseControlFactory extends ControlFactory {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the response control factory.
|
||||
*/
|
||||
public DefaultResponseControlFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of a response control class from a more
|
||||
* generic control class (BasicControl).
|
||||
*
|
||||
* @param ctl A non-null control.
|
||||
* @return The LDAP control created or null if it cannot be created.
|
||||
* Null indicates that another factory should be attempted.
|
||||
* @exception NamingException if this control factory encountered an
|
||||
* error condition while attempting to create the LDAP control,
|
||||
* and no other control factories are to be tried.
|
||||
*/
|
||||
public Control getControlInstance(Control ctl)
|
||||
throws NamingException {
|
||||
|
||||
String id = ctl.getID();
|
||||
//System.out.println(id);
|
||||
|
||||
try {
|
||||
if (id.equals(SortResponseControl.OID)) {
|
||||
return new SortResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
} else if (id.equals(PagedResultsResponseControl.OID)) {
|
||||
return new PagedResultsResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
} else if (id.equals(EntryChangeResponseControl.OID)) {
|
||||
return new EntryChangeResponseControl(id, ctl.isCritical(),
|
||||
ctl.getEncodedValue());
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
113
jdkSrc/jdk8/com/sun/jndi/ldap/DigestClientId.java
Normal file
113
jdkSrc/jdk8/com/sun/jndi/ldap/DigestClientId.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, 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.ldap;
|
||||
|
||||
import java.util.Arrays; // JDK 1.2
|
||||
import java.util.Hashtable;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Extends SimpleClientId to add property values specific for Digest-MD5.
|
||||
* This includes:
|
||||
* realm, authzid, qop, strength, maxbuffer, mutual-auth, reuse,
|
||||
* all policy-related selection properties.
|
||||
* Two DigestClientIds are identical iff they pass the SimpleClientId
|
||||
* equals() test and that all of these property values are the same.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class DigestClientId extends SimpleClientId {
|
||||
private static final String[] SASL_PROPS = {
|
||||
"java.naming.security.sasl.authorizationId",
|
||||
"java.naming.security.sasl.realm",
|
||||
"javax.security.sasl.qop",
|
||||
"javax.security.sasl.strength",
|
||||
"javax.security.sasl.reuse",
|
||||
"javax.security.sasl.server.authentication",
|
||||
"javax.security.sasl.maxbuffer",
|
||||
"javax.security.sasl.policy.noplaintext",
|
||||
"javax.security.sasl.policy.noactive",
|
||||
"javax.security.sasl.policy.nodictionary",
|
||||
"javax.security.sasl.policy.noanonymous",
|
||||
"javax.security.sasl.policy.forward",
|
||||
"javax.security.sasl.policy.credentials",
|
||||
};
|
||||
|
||||
final private String[] propvals;
|
||||
final private int myHash;
|
||||
|
||||
DigestClientId(int version, String hostname, int port,
|
||||
String protocol, Control[] bindCtls, OutputStream trace,
|
||||
String socketFactory, String username,
|
||||
Object passwd, Hashtable<?,?> env) {
|
||||
|
||||
super(version, hostname, port, protocol, bindCtls, trace,
|
||||
socketFactory, username, passwd);
|
||||
|
||||
if (env == null) {
|
||||
propvals = null;
|
||||
} else {
|
||||
// Could be smarter and apply default values for props
|
||||
// but for now, we just record and check exact matches
|
||||
propvals = new String[SASL_PROPS.length];
|
||||
for (int i = 0; i < SASL_PROPS.length; i++) {
|
||||
propvals[i] = (String) env.get(SASL_PROPS[i]);
|
||||
}
|
||||
}
|
||||
myHash = super.hashCode() ^ Arrays.hashCode(propvals);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DigestClientId)) {
|
||||
return false;
|
||||
}
|
||||
DigestClientId other = (DigestClientId)obj;
|
||||
return myHash == other.myHash
|
||||
&& super.equals(obj)
|
||||
&& Arrays.equals(propvals, other.propvals);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (propvals != null) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < propvals.length; i++) {
|
||||
buf.append(':');
|
||||
if (propvals[i] != null) {
|
||||
buf.append(propvals[i]);
|
||||
}
|
||||
}
|
||||
return super.toString() + buf.toString();
|
||||
} else {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
167
jdkSrc/jdk8/com/sun/jndi/ldap/EntryChangeResponseControl.java
Normal file
167
jdkSrc/jdk8/com/sun/jndi/ldap/EntryChangeResponseControl.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Response Control for entry-change
|
||||
* notification as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
*
|
||||
* The control's value has the following ASN.1 definition:
|
||||
* <pre>
|
||||
*
|
||||
* EntryChangeNotification ::= SEQUENCE {
|
||||
* changeType ENUMERATED {
|
||||
* add (1),
|
||||
* delete (2),
|
||||
* modify (4),
|
||||
* modDN (8)
|
||||
* },
|
||||
* previousDN LDAPDN OPTIONAL, -- modifyDN ops. only
|
||||
* changeNumber INTEGER OPTIONAL, -- if supported
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see PersistentSearchControl
|
||||
* @see com.sun.jndi.ldap.ctl.ResponseControlFactory ResponseControlFactory
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class EntryChangeResponseControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The entry-change response control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.7.
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.7";
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been added.
|
||||
*/
|
||||
public static final int ADD = 1;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been deleted.
|
||||
*/
|
||||
public static final int DELETE = 2;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been modified.
|
||||
*/
|
||||
public static final int MODIFY = 4;
|
||||
|
||||
/**
|
||||
* Indicates an entry which has been renamed.
|
||||
*/
|
||||
public static final int RENAME = 8;
|
||||
|
||||
/**
|
||||
* The type of change that occurred.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private int changeType;
|
||||
|
||||
/**
|
||||
* The previous distinguished name (only applies to RENAME changes).
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private String previousDN = null;
|
||||
|
||||
/**
|
||||
* The change number (if supported by the server).
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private long changeNumber = -1L;
|
||||
|
||||
private static final long serialVersionUID = -2087354136750180511L;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of EntryChangeResponseControl.
|
||||
*
|
||||
* @param id The control's object identifier string.
|
||||
* @param criticality The control's criticality.
|
||||
* @param value The control's ASN.1 BER encoded value.
|
||||
* May be null.
|
||||
* @exception IOException if an error is encountered
|
||||
* while decoding the control's value.
|
||||
*/
|
||||
public EntryChangeResponseControl(String id, boolean criticality,
|
||||
byte[] value) throws IOException {
|
||||
|
||||
super(id, criticality, value);
|
||||
|
||||
// decode value
|
||||
if ((value != null) && (value.length > 0)) {
|
||||
BerDecoder ber = new BerDecoder(value, 0, value.length);
|
||||
|
||||
ber.parseSeq(null);
|
||||
changeType = ber.parseEnumeration();
|
||||
|
||||
if ((ber.bytesLeft() > 0) && (ber.peekByte() == Ber.ASN_OCTET_STR)){
|
||||
previousDN = ber.parseString(true);
|
||||
}
|
||||
if ((ber.bytesLeft() > 0) && (ber.peekByte() == Ber.ASN_INTEGER)) {
|
||||
changeNumber = ber.parseInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the type of change that occurred.
|
||||
*
|
||||
* @return The type of change.
|
||||
*/
|
||||
public int getChangeType() {
|
||||
return changeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previous distinguished name of the entry before it was
|
||||
* renamed and/or moved. This method applies only to RENAME changes.
|
||||
*
|
||||
* @return The previous distinguished name or null if not applicable.
|
||||
*/
|
||||
public String getPreviousDN() {
|
||||
return previousDN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the change number assigned by the server for this change.
|
||||
* Returns -1 if this feature is not supported by the server.
|
||||
*
|
||||
* @return The change number or -1 if unsupported.
|
||||
*/
|
||||
public long getChangeNumber() {
|
||||
return changeNumber;
|
||||
}
|
||||
}
|
||||
176
jdkSrc/jdk8/com/sun/jndi/ldap/EventQueue.java
Normal file
176
jdkSrc/jdk8/com/sun/jndi/ldap/EventQueue.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.EventObject;
|
||||
|
||||
import javax.naming.event.NamingEvent;
|
||||
import javax.naming.event.NamingExceptionEvent;
|
||||
import javax.naming.event.NamingListener;
|
||||
import javax.naming.ldap.UnsolicitedNotificationEvent;
|
||||
import javax.naming.ldap.UnsolicitedNotificationListener;
|
||||
|
||||
/**
|
||||
* Package private class used by EventSupport to dispatch events.
|
||||
* This class implements an event queue, and a dispatcher thread that
|
||||
* dequeues and dispatches events from the queue.
|
||||
*
|
||||
* Pieces stolen from sun.misc.Queue.
|
||||
*
|
||||
* @author Bill Shannon (from javax.mail.event)
|
||||
* @author Rosanna Lee (modified for JNDI-related events)
|
||||
*/
|
||||
final class EventQueue implements Runnable {
|
||||
final static private boolean debug = false;
|
||||
|
||||
private static class QueueElement {
|
||||
QueueElement next = null;
|
||||
QueueElement prev = null;
|
||||
EventObject event = null;
|
||||
Vector<NamingListener> vector = null;
|
||||
|
||||
QueueElement(EventObject event, Vector<NamingListener> vector) {
|
||||
this.event = event;
|
||||
this.vector = vector;
|
||||
}
|
||||
}
|
||||
|
||||
private QueueElement head = null;
|
||||
private QueueElement tail = null;
|
||||
private Thread qThread;
|
||||
|
||||
// package private
|
||||
EventQueue() {
|
||||
qThread = Obj.helper.createThread(this);
|
||||
qThread.setDaemon(true); // not a user thread
|
||||
qThread.start();
|
||||
}
|
||||
|
||||
// package private;
|
||||
/**
|
||||
* Enqueue an event.
|
||||
* @param event Either a <tt>NamingExceptionEvent</tt> or a subclass
|
||||
* of <tt>NamingEvent</tt> or
|
||||
* <tt>UnsolicitedNotificatoniEvent</tt>.
|
||||
* If it is a subclass of <tt>NamingEvent</tt>, all listeners must implement
|
||||
* the corresponding subinterface of <tt>NamingListener</tt>.
|
||||
* For example, for a <tt>ObjectAddedEvent</tt>, all listeners <em>must</em>
|
||||
* implement the <tt>ObjectAddedListener</tt> interface.
|
||||
* <em>The current implementation does not check this before dispatching
|
||||
* the event.</em>
|
||||
* If the event is a <tt>NamingExceptionEvent</tt>, then all listeners
|
||||
* are notified.
|
||||
* @param vector List of NamingListeners that will be notified of event.
|
||||
*/
|
||||
synchronized void enqueue(EventObject event, Vector<NamingListener> vector) {
|
||||
QueueElement newElt = new QueueElement(event, vector);
|
||||
|
||||
if (head == null) {
|
||||
head = newElt;
|
||||
tail = newElt;
|
||||
} else {
|
||||
newElt.next = head;
|
||||
head.prev = newElt;
|
||||
head = newElt;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeue the oldest object on the queue.
|
||||
* Used only by the run() method.
|
||||
*
|
||||
* @return the oldest object on the queue.
|
||||
* @exception java.lang.InterruptedException if any thread has
|
||||
* interrupted this thread.
|
||||
*/
|
||||
private synchronized QueueElement dequeue()
|
||||
throws InterruptedException {
|
||||
while (tail == null)
|
||||
wait();
|
||||
QueueElement elt = tail;
|
||||
tail = elt.prev;
|
||||
if (tail == null) {
|
||||
head = null;
|
||||
} else {
|
||||
tail.next = null;
|
||||
}
|
||||
elt.prev = elt.next = null;
|
||||
return elt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull events off the queue and dispatch them.
|
||||
*/
|
||||
public void run() {
|
||||
QueueElement qe;
|
||||
|
||||
try {
|
||||
while ((qe = dequeue()) != null) {
|
||||
EventObject e = qe.event;
|
||||
Vector<NamingListener> v = qe.vector;
|
||||
|
||||
for (int i = 0; i < v.size(); i++) {
|
||||
|
||||
// Dispatch to corresponding NamingListener
|
||||
// The listener should only be getting the event that
|
||||
// it is interested in. (No need to check mask or
|
||||
// instanceof subinterfaces.)
|
||||
// It is the responsibility of the enqueuer to
|
||||
// only enqueue events with listseners of the correct type.
|
||||
|
||||
if (e instanceof NamingEvent) {
|
||||
((NamingEvent)e).dispatch(v.elementAt(i));
|
||||
|
||||
// An exception occurred: if notify all naming listeners
|
||||
} else if (e instanceof NamingExceptionEvent) {
|
||||
((NamingExceptionEvent)e).dispatch(v.elementAt(i));
|
||||
} else if (e instanceof UnsolicitedNotificationEvent) {
|
||||
((UnsolicitedNotificationEvent)e).dispatch(
|
||||
(UnsolicitedNotificationListener)v.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
qe = null; e = null; v = null;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// just die
|
||||
}
|
||||
}
|
||||
|
||||
// package private; used by EventSupport;
|
||||
/**
|
||||
* Stop the dispatcher so we can be destroyed.
|
||||
*/
|
||||
void stop() {
|
||||
if (debug) System.err.println("EventQueue stopping");
|
||||
if (qThread != null) {
|
||||
qThread.interrupt(); // kill our thread
|
||||
qThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
352
jdkSrc/jdk8/com/sun/jndi/ldap/EventSupport.java
Normal file
352
jdkSrc/jdk8/com/sun/jndi/ldap/EventSupport.java
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2017, 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.ldap;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.EventObject;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.event.*;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.ldap.UnsolicitedNotificationListener;
|
||||
import javax.naming.ldap.UnsolicitedNotificationEvent;
|
||||
import javax.naming.ldap.UnsolicitedNotification;
|
||||
|
||||
/**
|
||||
* This is a utility class that can be used by a context that supports
|
||||
* event notification. You can use an instance of this class as a member field
|
||||
* of your context and delegate various work to it.
|
||||
* It is currently structured so that each context should have its own
|
||||
* EventSupport (instead of static version shared by all contexts
|
||||
* of a service provider).
|
||||
*<p>
|
||||
* This class supports two types of listeners: those that register for
|
||||
* NamingEvents, and those for UnsolicitedNotificationEvents (they can be mixed
|
||||
* into the same listener).
|
||||
* For NamingEvent listeners, it maintains a hashtable that maps
|
||||
* registration requests--the key--to
|
||||
* <em>notifiers</em>--the value. Each registration request consists of:
|
||||
*<ul>
|
||||
*<li>The name argument of the registration.
|
||||
*<li>The filter (default is "(objectclass=*)").
|
||||
*<li>The search controls (default is null SearchControls).
|
||||
*<li>The events that the listener is interested in. This is determined by
|
||||
* finding out which <tt>NamingListener</tt> interface the listener supports.
|
||||
*</ul>
|
||||
*<p>
|
||||
*A notifier (<tt>NamingEventNotifier</tt>) is a worker thread that is responsible
|
||||
*for gathering information for generating events requested by its listeners.
|
||||
*Each notifier maintains its own list of listeners; these listeners have
|
||||
*all made the same registration request (at different times) and implements
|
||||
*the same <tt>NamingListener</tt> interfaces.
|
||||
*<p>
|
||||
*For unsolicited listeners, this class maintains a vector, unsolicited.
|
||||
*When an unsolicited listener is registered, this class adds itself
|
||||
*to the context's LdapClient. When LdapClient receives an unsolicited
|
||||
*notification, it notifies this EventSupport to fire an event to the
|
||||
*the listeners. Special handling in LdapClient is done for the DISCONNECT
|
||||
*notification. [It results in the EventSupport firing also a
|
||||
*NamingExceptionEvent to the unsolicited listeners.]
|
||||
*<p>
|
||||
*
|
||||
*When a context no longer needs this EventSupport, it should invoke
|
||||
*cleanup() on it.
|
||||
*<p>
|
||||
*<h4>Registration</h4>
|
||||
*When a registration request is made, this class attempts to find an
|
||||
*existing notifier that's already working on the request. If one is
|
||||
*found, the listener is added to the notifier's list. If one is not found,
|
||||
*a new notifier is created for the listener.
|
||||
*
|
||||
*<h4>Deregistration</h4>
|
||||
*When a deregistration request is made, this class attemps to find its
|
||||
*corresponding notifier. If the notifier is found, the listener is removed
|
||||
*from the notifier's list. If the listener is the last listener on the list,
|
||||
*the notifier's thread is terminated and removed from this class's hashtable.
|
||||
*Nothing happens if the notifier is not found.
|
||||
*
|
||||
*<h4>Event Dispatching</h4>
|
||||
*The notifiers are responsible for gather information for generating events
|
||||
*requested by their respective listeners. When a notifier gets sufficient
|
||||
*information to generate an event, it creates invokes the
|
||||
*appropriate <tt>fireXXXEvent</tt> on this class with the information and list of
|
||||
*listeners. This causes an event and the list of listeners to be added
|
||||
*to the <em>event queue</em>.
|
||||
*This class maintains an event queue and a dispatching thread that dequeues
|
||||
*events from the queue and dispatches them to the listeners.
|
||||
*
|
||||
*<h4>Synchronization</h4>
|
||||
*This class is used by the main thread (LdapCtx) to add/remove listeners.
|
||||
*It is also used asynchronously by NamingEventNotifiers threads and
|
||||
*the context's Connection thread. It is used by the notifier threads to
|
||||
*queue events and to update the notifiers list when the notifiers exit.
|
||||
*It is used by the Connection thread to fire unsolicited notifications.
|
||||
*Methods that access/update the 'unsolicited' and 'notifiers' lists are
|
||||
*thread-safe.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class EventSupport {
|
||||
final static private boolean debug = false;
|
||||
|
||||
private LdapCtx ctx;
|
||||
|
||||
/**
|
||||
* NamingEventNotifiers; hashed by search arguments;
|
||||
*/
|
||||
private Hashtable<NotifierArgs, NamingEventNotifier> notifiers =
|
||||
new Hashtable<>(11);
|
||||
|
||||
/**
|
||||
* List of unsolicited notification listeners.
|
||||
*/
|
||||
private Vector<UnsolicitedNotificationListener> unsolicited = null;
|
||||
|
||||
/**
|
||||
* Constructs EventSupport for ctx.
|
||||
* <em>Do we need to record the name of the target context?
|
||||
* Or can we assume that EventSupport is called on a resolved
|
||||
* context? Do we need other add/remove-NamingListener methods?
|
||||
* package private;
|
||||
*/
|
||||
EventSupport(LdapCtx ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt>.
|
||||
*/
|
||||
/*
|
||||
* Make the add/removeNamingListeners synchronized to:
|
||||
* 1. protect usage of 'unsolicited', which may be read by
|
||||
* the Connection thread when dispatching unsolicited notification.
|
||||
* 2. ensure that NamingEventNotifier thread's access to 'notifiers'
|
||||
* is safe
|
||||
*/
|
||||
synchronized void addNamingListener(String nm, int scope,
|
||||
NamingListener l) throws NamingException {
|
||||
|
||||
if (l instanceof ObjectChangeListener ||
|
||||
l instanceof NamespaceChangeListener) {
|
||||
NotifierArgs args = new NotifierArgs(nm, scope, l);
|
||||
|
||||
NamingEventNotifier notifier = notifiers.get(args);
|
||||
if (notifier == null) {
|
||||
notifier = new NamingEventNotifier(this, ctx, args, l);
|
||||
notifiers.put(args, notifier);
|
||||
} else {
|
||||
notifier.addNamingListener(l);
|
||||
}
|
||||
}
|
||||
if (l instanceof UnsolicitedNotificationListener) {
|
||||
// Add listener to this's list of unsolicited notifiers
|
||||
if (unsolicited == null) {
|
||||
unsolicited = new Vector<>(3);
|
||||
}
|
||||
|
||||
unsolicited.addElement((UnsolicitedNotificationListener)l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt>
|
||||
* and filter.
|
||||
*/
|
||||
synchronized void addNamingListener(String nm, String filter,
|
||||
SearchControls ctls, NamingListener l) throws NamingException {
|
||||
|
||||
if (l instanceof ObjectChangeListener ||
|
||||
l instanceof NamespaceChangeListener) {
|
||||
NotifierArgs args = new NotifierArgs(nm, filter, ctls, l);
|
||||
|
||||
NamingEventNotifier notifier = notifiers.get(args);
|
||||
if (notifier == null) {
|
||||
notifier = new NamingEventNotifier(this, ctx, args, l);
|
||||
notifiers.put(args, notifier);
|
||||
} else {
|
||||
notifier.addNamingListener(l);
|
||||
}
|
||||
}
|
||||
if (l instanceof UnsolicitedNotificationListener) {
|
||||
// Add listener to this's list of unsolicited notifiers
|
||||
if (unsolicited == null) {
|
||||
unsolicited = new Vector<>(3);
|
||||
}
|
||||
unsolicited.addElement((UnsolicitedNotificationListener)l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes <tt>l</tt> from all notifiers in this context.
|
||||
*/
|
||||
synchronized void removeNamingListener(NamingListener l) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener");
|
||||
}
|
||||
// Go through list of notifiers, remove 'l' from each.
|
||||
// If 'l' is notifier's only listener, remove notifier too.
|
||||
Iterator<NamingEventNotifier> iterator = notifiers.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
NamingEventNotifier notifier = iterator.next();
|
||||
if (notifier != null) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing listener from notifier");
|
||||
}
|
||||
notifier.removeNamingListener(l);
|
||||
if (!notifier.hasNamingListeners()) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport stopping notifier");
|
||||
}
|
||||
notifier.stop();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove from list of unsolicited notifier
|
||||
if (debug) {
|
||||
System.err.println("EventSupport removing unsolicited: " + unsolicited);
|
||||
}
|
||||
if (unsolicited != null) {
|
||||
unsolicited.removeElement(l);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized boolean hasUnsolicited() {
|
||||
return (unsolicited != null && unsolicited.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* package private;
|
||||
* Called by NamingEventNotifier to remove itself when it encounters
|
||||
* a NamingException.
|
||||
*/
|
||||
synchronized void removeDeadNotifier(NotifierArgs info) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport.removeDeadNotifier: " + info.name);
|
||||
}
|
||||
notifiers.remove(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event to unsolicited listeners.
|
||||
* package private;
|
||||
* Called by LdapCtx when its clnt receives an unsolicited notification.
|
||||
*/
|
||||
synchronized void fireUnsolicited(Object obj) {
|
||||
if (debug) {
|
||||
System.err.println("EventSupport.fireUnsolicited: " + obj + " "
|
||||
+ unsolicited);
|
||||
}
|
||||
if (unsolicited == null || unsolicited.size() == 0) {
|
||||
// This shouldn't really happen, but might in case
|
||||
// there is a timing problem that removes a listener
|
||||
// before a fired event event reaches here.
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj instanceof UnsolicitedNotification) {
|
||||
|
||||
// Fire UnsolicitedNotification to unsolicited listeners
|
||||
|
||||
UnsolicitedNotificationEvent evt =
|
||||
new UnsolicitedNotificationEvent(ctx, (UnsolicitedNotification)obj);
|
||||
queueEvent(evt, unsolicited);
|
||||
|
||||
} else if (obj instanceof NamingException) {
|
||||
|
||||
// Fire NamingExceptionEvent to unsolicited listeners.
|
||||
|
||||
NamingExceptionEvent evt =
|
||||
new NamingExceptionEvent(ctx, (NamingException)obj);
|
||||
queueEvent(evt, unsolicited);
|
||||
|
||||
// When an exception occurs, the unsolicited listeners
|
||||
// are automatically deregistered.
|
||||
// When LdapClient.processUnsolicited() fires a NamingException,
|
||||
// it will update its listener list so we don't have to.
|
||||
// Likewise for LdapCtx.
|
||||
|
||||
unsolicited = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops notifier threads that are collecting event data and
|
||||
* stops the event queue from dispatching events.
|
||||
* Package private; used by LdapCtx.
|
||||
*/
|
||||
synchronized void cleanup() {
|
||||
if (debug) System.err.println("EventSupport clean up");
|
||||
if (notifiers != null) {
|
||||
for (NamingEventNotifier notifier : notifiers.values()) {
|
||||
notifier.stop();
|
||||
}
|
||||
notifiers = null;
|
||||
}
|
||||
if (eventQueue != null) {
|
||||
eventQueue.stop();
|
||||
eventQueue = null;
|
||||
}
|
||||
// %%% Should we fire NamingExceptionEvents to unsolicited listeners?
|
||||
}
|
||||
|
||||
/*
|
||||
* The queue of events to be delivered.
|
||||
*/
|
||||
private EventQueue eventQueue;
|
||||
|
||||
/**
|
||||
* Add the event and vector of listeners to the queue to be delivered.
|
||||
* An event dispatcher thread dequeues events from the queue and dispatches
|
||||
* them to the registered listeners.
|
||||
* Package private; used by NamingEventNotifier to fire events
|
||||
*/
|
||||
synchronized void queueEvent(EventObject event,
|
||||
Vector<? extends NamingListener> vector) {
|
||||
if (eventQueue == null)
|
||||
eventQueue = new EventQueue();
|
||||
|
||||
/*
|
||||
* Copy the vector in order to freeze the state of the set
|
||||
* of EventListeners the event should be delivered to prior
|
||||
* to delivery. This ensures that any changes made to the
|
||||
* Vector from a target listener's method during the delivery
|
||||
* of this event will not take effect until after the event is
|
||||
* delivered.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
Vector<NamingListener> v =
|
||||
(Vector<NamingListener>)vector.clone();
|
||||
eventQueue.enqueue(event, v);
|
||||
}
|
||||
|
||||
// No finalize() needed because EventSupport is always owned by
|
||||
// an LdapCtx. LdapCtx's finalize() and close() always call cleanup() so
|
||||
// there is no need for EventSupport to have a finalize().
|
||||
}
|
||||
870
jdkSrc/jdk8/com/sun/jndi/ldap/Filter.java
Normal file
870
jdkSrc/jdk8/com/sun/jndi/ldap/Filter.java
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.InvalidSearchFilterException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LDAP (RFC-1960) and LDAPv3 (RFC-2254) search filters.
|
||||
*
|
||||
* @author Xuelei Fan
|
||||
* @author Vincent Ryan
|
||||
* @author Jagane Sundar
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final class Filter {
|
||||
|
||||
/**
|
||||
* First convert filter string into byte[].
|
||||
* For LDAP v3, the conversion uses Unicode -> UTF8
|
||||
* For LDAP v2, the conversion uses Unicode -> ISO 8859 (Latin-1)
|
||||
*
|
||||
* Then parse the byte[] as a filter, converting \hh to
|
||||
* a single byte, and encoding the resulting filter
|
||||
* into the supplied BER buffer
|
||||
*/
|
||||
static void encodeFilterString(BerEncoder ber, String filterStr,
|
||||
boolean isLdapv3) throws IOException, NamingException {
|
||||
|
||||
if ((filterStr == null) || (filterStr.equals(""))) {
|
||||
throw new InvalidSearchFilterException("Empty filter");
|
||||
}
|
||||
byte[] filter;
|
||||
int filterLen;
|
||||
if (isLdapv3) {
|
||||
filter = filterStr.getBytes("UTF8");
|
||||
} else {
|
||||
filter = filterStr.getBytes("8859_1");
|
||||
}
|
||||
filterLen = filter.length;
|
||||
if (dbg) {
|
||||
dbgIndent = 0;
|
||||
System.err.println("String filter: " + filterStr);
|
||||
System.err.println("size: " + filterLen);
|
||||
dprint("original: ", filter, 0, filterLen);
|
||||
}
|
||||
|
||||
encodeFilter(ber, filter, 0, filterLen);
|
||||
}
|
||||
|
||||
private static void encodeFilter(BerEncoder ber, byte[] filter,
|
||||
int filterStart, int filterEnd) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encFilter: ", filter, filterStart, filterEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
if ((filterEnd - filterStart) <= 0) {
|
||||
throw new InvalidSearchFilterException("Empty filter");
|
||||
}
|
||||
|
||||
int nextOffset;
|
||||
int parens, balance;
|
||||
boolean escape;
|
||||
|
||||
parens = 0;
|
||||
|
||||
int filtOffset[] = new int[1];
|
||||
|
||||
for (filtOffset[0] = filterStart; filtOffset[0] < filterEnd;) {
|
||||
switch (filter[filtOffset[0]]) {
|
||||
case '(':
|
||||
filtOffset[0]++;
|
||||
parens++;
|
||||
switch (filter[filtOffset[0]]) {
|
||||
case '&':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_AND, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_OR, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
encodeComplexFilter(ber, filter,
|
||||
LDAP_FILTER_NOT, filtOffset, filterEnd);
|
||||
// filtOffset[0] has pointed to char after right paren
|
||||
parens--;
|
||||
break;
|
||||
|
||||
default:
|
||||
balance = 1;
|
||||
escape = false;
|
||||
nextOffset = filtOffset[0];
|
||||
while (nextOffset < filterEnd && balance > 0) {
|
||||
if (!escape) {
|
||||
if (filter[nextOffset] == '(')
|
||||
balance++;
|
||||
else if (filter[nextOffset] == ')')
|
||||
balance--;
|
||||
}
|
||||
if (filter[nextOffset] == '\\' && !escape)
|
||||
escape = true;
|
||||
else
|
||||
escape = false;
|
||||
if (balance > 0)
|
||||
nextOffset++;
|
||||
}
|
||||
if (balance != 0)
|
||||
throw new InvalidSearchFilterException(
|
||||
"Unbalanced parenthesis");
|
||||
|
||||
encodeSimpleFilter(ber, filter, filtOffset[0], nextOffset);
|
||||
|
||||
// points to the char after right paren.
|
||||
filtOffset[0] = nextOffset + 1;
|
||||
|
||||
parens--;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ')':
|
||||
//
|
||||
// End of sequence
|
||||
//
|
||||
ber.endSeq();
|
||||
filtOffset[0]++;
|
||||
parens--;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
filtOffset[0]++;
|
||||
break;
|
||||
|
||||
default: // assume simple type=value filter
|
||||
encodeSimpleFilter(ber, filter, filtOffset[0], filterEnd);
|
||||
filtOffset[0] = filterEnd; // force break from outer
|
||||
break;
|
||||
}
|
||||
|
||||
if (parens < 0) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"Unbalanced parenthesis");
|
||||
}
|
||||
}
|
||||
|
||||
if (parens != 0) {
|
||||
throw new InvalidSearchFilterException("Unbalanced parenthesis");
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* convert character 'c' that represents a hexadecimal digit to an integer.
|
||||
* if 'c' is not a hexadecimal digit [0-9A-Fa-f], -1 is returned.
|
||||
* otherwise the converted value is returned.
|
||||
*/
|
||||
private static int hexchar2int( byte c ) {
|
||||
if ( c >= '0' && c <= '9' ) {
|
||||
return( c - '0' );
|
||||
}
|
||||
if ( c >= 'A' && c <= 'F' ) {
|
||||
return( c - 'A' + 10 );
|
||||
}
|
||||
if ( c >= 'a' && c <= 'f' ) {
|
||||
return( c - 'a' + 10 );
|
||||
}
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
// called by the LdapClient.compare method
|
||||
static byte[] unescapeFilterValue(byte[] orig, int start, int end)
|
||||
throws NamingException {
|
||||
boolean escape = false, escStart = false;
|
||||
int ival;
|
||||
byte ch;
|
||||
|
||||
if (dbg) {
|
||||
dprint("unescape: " , orig, start, end);
|
||||
}
|
||||
|
||||
int len = end - start;
|
||||
byte tbuf[] = new byte[len];
|
||||
int j = 0;
|
||||
for (int i = start; i < end; i++) {
|
||||
ch = orig[i];
|
||||
if (escape) {
|
||||
// Try LDAP V3 escape (\xx)
|
||||
if ((ival = hexchar2int(ch)) < 0) {
|
||||
|
||||
/**
|
||||
* If there is no hex char following a '\' when
|
||||
* parsing a LDAP v3 filter (illegal by v3 way)
|
||||
* we fallback to the way we unescape in v2.
|
||||
*/
|
||||
if (escStart) {
|
||||
// V2: \* \( \)
|
||||
escape = false;
|
||||
tbuf[j++] = ch;
|
||||
} else {
|
||||
// escaping already started but we can't find 2nd hex
|
||||
throw new InvalidSearchFilterException("invalid escape sequence: " + orig);
|
||||
}
|
||||
} else {
|
||||
if (escStart) {
|
||||
tbuf[j] = (byte)(ival<<4);
|
||||
escStart = false;
|
||||
} else {
|
||||
tbuf[j++] |= (byte)ival;
|
||||
escape = false;
|
||||
}
|
||||
}
|
||||
} else if (ch != '\\') {
|
||||
tbuf[j++] = ch;
|
||||
escape = false;
|
||||
} else {
|
||||
escStart = escape = true;
|
||||
}
|
||||
}
|
||||
byte[] answer = new byte[j];
|
||||
System.arraycopy(tbuf, 0, answer, 0, j);
|
||||
if (dbg) {
|
||||
Ber.dumpBER(System.err, "", answer, 0, j);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
private static int indexOf(byte[] str, char ch, int start, int end) {
|
||||
for (int i = start; i < end; i++) {
|
||||
if (str[i] == ch)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int indexOf(byte[] str, String target, int start, int end) {
|
||||
int where = indexOf(str, target.charAt(0), start, end);
|
||||
if (where >= 0) {
|
||||
for (int i = 1; i < target.length(); i++) {
|
||||
if (str[where+i] != target.charAt(i)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
private static int findUnescaped(byte[] str, char ch, int start, int end) {
|
||||
while (start < end) {
|
||||
int where = indexOf(str, ch, start, end);
|
||||
|
||||
/*
|
||||
* Count the immediate preceding '\' to find out if
|
||||
* this is an escaped '*'. This is a made-up way for
|
||||
* parsing an escaped '*' in v2. This is how the other leading
|
||||
* SDK vendors interpret v2.
|
||||
* For v3 we fallback to the way we parse "\*" in v2.
|
||||
* It's not legal in v3 to use "\*" to escape '*'; the right
|
||||
* way is to use "\2a" instead.
|
||||
*/
|
||||
int backSlashPos;
|
||||
int backSlashCnt = 0;
|
||||
for (backSlashPos = where - 1;
|
||||
((backSlashPos >= start) && (str[backSlashPos] == '\\'));
|
||||
backSlashPos--, backSlashCnt++);
|
||||
|
||||
// if at start of string, or not there at all, or if not escaped
|
||||
if (where == start || where == -1 || ((backSlashCnt % 2) == 0))
|
||||
return where;
|
||||
|
||||
// start search after escaped star
|
||||
start = where + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private static void encodeSimpleFilter(BerEncoder ber, byte[] filter,
|
||||
int filtStart, int filtEnd) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encSimpleFilter: ", filter, filtStart, filtEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
String type, value;
|
||||
int valueStart, valueEnd, typeStart, typeEnd;
|
||||
|
||||
int eq;
|
||||
if ((eq = indexOf(filter, '=', filtStart, filtEnd)) == -1) {
|
||||
throw new InvalidSearchFilterException("Missing 'equals'");
|
||||
}
|
||||
|
||||
|
||||
valueStart = eq + 1; // value starts after equal sign
|
||||
valueEnd = filtEnd;
|
||||
typeStart = filtStart; // beginning of string
|
||||
|
||||
int ftype;
|
||||
|
||||
switch (filter[eq - 1]) {
|
||||
case '<':
|
||||
ftype = LDAP_FILTER_LE;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case '>':
|
||||
ftype = LDAP_FILTER_GE;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case '~':
|
||||
ftype = LDAP_FILTER_APPROX;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
case ':':
|
||||
ftype = LDAP_FILTER_EXT;
|
||||
typeEnd = eq - 1;
|
||||
break;
|
||||
default:
|
||||
typeEnd = eq;
|
||||
//initializing ftype to make the compiler happy
|
||||
ftype = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
System.err.println("type: " + typeStart + ", " + typeEnd);
|
||||
System.err.println("value: " + valueStart + ", " + valueEnd);
|
||||
}
|
||||
|
||||
// check validity of type
|
||||
//
|
||||
// RFC4512 defines the type as the following ABNF:
|
||||
// attr = attributedescription
|
||||
// attributedescription = attributetype options
|
||||
// attributetype = oid
|
||||
// oid = descr / numericoid
|
||||
// descr = keystring
|
||||
// keystring = leadkeychar *keychar
|
||||
// leadkeychar = ALPHA
|
||||
// keychar = ALPHA / DIGIT / HYPHEN
|
||||
// numericoid = number 1*( DOT number )
|
||||
// number = DIGIT / ( LDIGIT 1*DIGIT )
|
||||
// options = *( SEMI option )
|
||||
// option = 1*keychar
|
||||
//
|
||||
// And RFC4515 defines the extensible type as the following ABNF:
|
||||
// attr [dnattrs] [matchingrule] / [dnattrs] matchingrule
|
||||
int optionsStart = -1;
|
||||
int extensibleStart = -1;
|
||||
if ((filter[typeStart] >= '0' && filter[typeStart] <= '9') ||
|
||||
(filter[typeStart] >= 'A' && filter[typeStart] <= 'Z') ||
|
||||
(filter[typeStart] >= 'a' && filter[typeStart] <= 'z')) {
|
||||
|
||||
boolean isNumericOid =
|
||||
filter[typeStart] >= '0' && filter[typeStart] <= '9';
|
||||
for (int i = typeStart + 1; i < typeEnd; i++) {
|
||||
// ';' is an indicator of attribute options
|
||||
if (filter[i] == ';') {
|
||||
if (isNumericOid && filter[i - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// attribute options
|
||||
optionsStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// ':' is an indicator of extensible rules
|
||||
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
|
||||
if (isNumericOid && filter[i - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// extensible matching
|
||||
extensibleStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNumericOid) {
|
||||
// numeric object identifier
|
||||
if ((filter[i] == '.' && filter[i - 1] == '.') ||
|
||||
(filter[i] != '.' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9'))) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
} else {
|
||||
// descriptor
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[i] != '-' && filter[i] != '_' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9') &&
|
||||
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
|
||||
!(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ftype == LDAP_FILTER_EXT && filter[typeStart] == ':') {
|
||||
// extensible matching
|
||||
extensibleStart = typeStart;
|
||||
} else {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// check attribute options
|
||||
if (optionsStart > 0) {
|
||||
for (int i = optionsStart + 1; i < typeEnd; i++) {
|
||||
if (filter[i] == ';') {
|
||||
if (filter[i - 1] == ';') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ':' is an indicator of extensible rules
|
||||
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
|
||||
if (filter[i - 1] == ';') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
// extensible matching
|
||||
extensibleStart = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[i] != '-' && filter[i] != '_' &&
|
||||
!(filter[i] >= '0' && filter[i] <= '9') &&
|
||||
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
|
||||
!(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check extensible matching
|
||||
if (extensibleStart > 0) {
|
||||
boolean isMatchingRule = false;
|
||||
for (int i = extensibleStart + 1; i < typeEnd; i++) {
|
||||
if (filter[i] == ':') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
} else if ((filter[i] >= '0' && filter[i] <= '9') ||
|
||||
(filter[i] >= 'A' && filter[i] <= 'Z') ||
|
||||
(filter[i] >= 'a' && filter[i] <= 'z')) {
|
||||
boolean isNumericOid = filter[i] >= '0' && filter[i] <= '9';
|
||||
i++;
|
||||
for (int j = i; j < typeEnd; j++, i++) {
|
||||
// allows no more than two extensible rules
|
||||
if (filter[j] == ':') {
|
||||
if (isMatchingRule) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
if (isNumericOid && filter[j - 1] == '.') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
isMatchingRule = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNumericOid) {
|
||||
// numeric object identifier
|
||||
if ((filter[j] == '.' && filter[j - 1] == '.') ||
|
||||
(filter[j] != '.' &&
|
||||
!(filter[j] >= '0' && filter[j] <= '9'))) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
} else {
|
||||
// descriptor
|
||||
// The underscore ("_") character is not allowed by
|
||||
// the LDAP specification. We allow it here to
|
||||
// tolerate the incorrect use in practice.
|
||||
if (filter[j] != '-' && filter[j] != '_' &&
|
||||
!(filter[j] >= '0' && filter[j] <= '9') &&
|
||||
!(filter[j] >= 'A' && filter[j] <= 'Z') &&
|
||||
!(filter[j] >= 'a' && filter[j] <= 'z')) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the latest byte is not isolated
|
||||
if (filter[typeEnd - 1] == '.' || filter[typeEnd - 1] == ';' ||
|
||||
filter[typeEnd - 1] == ':') {
|
||||
throw new InvalidSearchFilterException(
|
||||
"invalid attribute description");
|
||||
}
|
||||
|
||||
if (typeEnd == eq) { // filter type is of "equal"
|
||||
if (findUnescaped(filter, '*', valueStart, valueEnd) == -1) {
|
||||
ftype = LDAP_FILTER_EQUALITY;
|
||||
} else if (filter[valueStart] == '*' &&
|
||||
valueStart == (valueEnd - 1)) {
|
||||
ftype = LDAP_FILTER_PRESENT;
|
||||
} else {
|
||||
encodeSubstringFilter(ber, filter,
|
||||
typeStart, typeEnd, valueStart, valueEnd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ftype == LDAP_FILTER_PRESENT) {
|
||||
ber.encodeOctetString(filter, ftype, typeStart, typeEnd-typeStart);
|
||||
} else if (ftype == LDAP_FILTER_EXT) {
|
||||
encodeExtensibleMatch(ber, filter,
|
||||
typeStart, typeEnd, valueStart, valueEnd);
|
||||
} else {
|
||||
ber.beginSeq(ftype);
|
||||
ber.encodeOctetString(filter, Ber.ASN_OCTET_STR,
|
||||
typeStart, typeEnd - typeStart);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, valueStart, valueEnd),
|
||||
Ber.ASN_OCTET_STR);
|
||||
ber.endSeq();
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
}
|
||||
|
||||
private static void encodeSubstringFilter(BerEncoder ber, byte[] filter,
|
||||
int typeStart, int typeEnd, int valueStart, int valueEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encSubstringFilter: type ", filter, typeStart, typeEnd);
|
||||
dprint(", val : ", filter, valueStart, valueEnd);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
ber.beginSeq(LDAP_FILTER_SUBSTRINGS);
|
||||
ber.encodeOctetString(filter, Ber.ASN_OCTET_STR,
|
||||
typeStart, typeEnd-typeStart);
|
||||
ber.beginSeq(LdapClient.LBER_SEQUENCE);
|
||||
int index;
|
||||
int previndex = valueStart;
|
||||
while ((index = findUnescaped(filter, '*', previndex, valueEnd)) != -1) {
|
||||
if (previndex == valueStart) {
|
||||
if (previndex < index) {
|
||||
if (dbg)
|
||||
System.err.println(
|
||||
"initial: " + previndex + "," + index);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, index),
|
||||
LDAP_SUBSTRING_INITIAL);
|
||||
}
|
||||
} else {
|
||||
if (previndex < index) {
|
||||
if (dbg)
|
||||
System.err.println("any: " + previndex + "," + index);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, index),
|
||||
LDAP_SUBSTRING_ANY);
|
||||
}
|
||||
}
|
||||
previndex = index + 1;
|
||||
}
|
||||
if (previndex < valueEnd) {
|
||||
if (dbg)
|
||||
System.err.println("final: " + previndex + "," + valueEnd);
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, previndex, valueEnd),
|
||||
LDAP_SUBSTRING_FINAL);
|
||||
}
|
||||
ber.endSeq();
|
||||
ber.endSeq();
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
}
|
||||
|
||||
// The complex filter types look like:
|
||||
// "&(type=val)(type=val)"
|
||||
// "|(type=val)(type=val)"
|
||||
// "!(type=val)"
|
||||
//
|
||||
// The filtOffset[0] pointing to the '&', '|', or '!'.
|
||||
//
|
||||
private static void encodeComplexFilter(BerEncoder ber, byte[] filter,
|
||||
int filterType, int filtOffset[], int filtEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encComplexFilter: ", filter, filtOffset[0], filtEnd);
|
||||
dprint(", type: " + Integer.toString(filterType, 16));
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
filtOffset[0]++;
|
||||
|
||||
ber.beginSeq(filterType);
|
||||
|
||||
int[] parens = findRightParen(filter, filtOffset, filtEnd);
|
||||
encodeFilterList(ber, filter, filterType, parens[0], parens[1]);
|
||||
|
||||
ber.endSeq();
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// filter at filtOffset[0] - 1 points to a (. Find ) that matches it
|
||||
// and return substring between the parens. Adjust filtOffset[0] to
|
||||
// point to char after right paren
|
||||
//
|
||||
private static int[] findRightParen(byte[] filter, int filtOffset[], int end)
|
||||
throws IOException, NamingException {
|
||||
|
||||
int balance = 1;
|
||||
boolean escape = false;
|
||||
int nextOffset = filtOffset[0];
|
||||
|
||||
while (nextOffset < end && balance > 0) {
|
||||
if (!escape) {
|
||||
if (filter[nextOffset] == '(')
|
||||
balance++;
|
||||
else if (filter[nextOffset] == ')')
|
||||
balance--;
|
||||
}
|
||||
if (filter[nextOffset] == '\\' && !escape)
|
||||
escape = true;
|
||||
else
|
||||
escape = false;
|
||||
if (balance > 0)
|
||||
nextOffset++;
|
||||
}
|
||||
if (balance != 0) {
|
||||
throw new InvalidSearchFilterException("Unbalanced parenthesis");
|
||||
}
|
||||
|
||||
// String tmp = filter.substring(filtOffset[0], nextOffset);
|
||||
|
||||
int[] tmp = new int[] {filtOffset[0], nextOffset};
|
||||
|
||||
filtOffset[0] = nextOffset + 1;
|
||||
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Encode filter list of type "(filter1)(filter2)..."
|
||||
//
|
||||
private static void encodeFilterList(BerEncoder ber, byte[] filter,
|
||||
int filterType, int start, int end) throws IOException, NamingException {
|
||||
|
||||
if (dbg) {
|
||||
dprint("encFilterList: ", filter, start, end);
|
||||
dbgIndent++;
|
||||
}
|
||||
|
||||
int filtOffset[] = new int[1];
|
||||
int listNumber = 0;
|
||||
for (filtOffset[0] = start; filtOffset[0] < end; filtOffset[0]++) {
|
||||
if (Character.isSpaceChar((char)filter[filtOffset[0]]))
|
||||
continue;
|
||||
|
||||
if ((filterType == LDAP_FILTER_NOT) && (listNumber > 0)) {
|
||||
throw new InvalidSearchFilterException(
|
||||
"Filter (!) cannot be followed by more than one filters");
|
||||
}
|
||||
|
||||
if (filter[filtOffset[0]] == '(') {
|
||||
continue;
|
||||
}
|
||||
|
||||
int[] parens = findRightParen(filter, filtOffset, end);
|
||||
|
||||
// add enclosing parens
|
||||
int len = parens[1]-parens[0];
|
||||
byte[] newfilter = new byte[len+2];
|
||||
System.arraycopy(filter, parens[0], newfilter, 1, len);
|
||||
newfilter[0] = (byte)'(';
|
||||
newfilter[len+1] = (byte)')';
|
||||
encodeFilter(ber, newfilter, 0, newfilter.length);
|
||||
|
||||
listNumber++;
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
dbgIndent--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Encode extensible match
|
||||
//
|
||||
private static void encodeExtensibleMatch(BerEncoder ber, byte[] filter,
|
||||
int matchStart, int matchEnd, int valueStart, int valueEnd)
|
||||
throws IOException, NamingException {
|
||||
|
||||
boolean matchDN = false;
|
||||
int colon;
|
||||
int colon2;
|
||||
int i;
|
||||
|
||||
ber.beginSeq(LDAP_FILTER_EXT);
|
||||
|
||||
// test for colon separator
|
||||
if ((colon = indexOf(filter, ':', matchStart, matchEnd)) >= 0) {
|
||||
|
||||
// test for match DN
|
||||
if ((i = indexOf(filter, ":dn", colon, matchEnd)) >= 0) {
|
||||
matchDN = true;
|
||||
}
|
||||
|
||||
// test for matching rule
|
||||
if (((colon2 = indexOf(filter, ':', colon + 1, matchEnd)) >= 0)
|
||||
|| (i == -1)) {
|
||||
|
||||
if (i == colon) {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon2 + 1, matchEnd - (colon2 + 1));
|
||||
|
||||
} else if ((i == colon2) && (i >= 0)) {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon + 1, colon2 - (colon + 1));
|
||||
|
||||
} else {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_RULE,
|
||||
colon + 1, matchEnd - (colon + 1));
|
||||
}
|
||||
}
|
||||
|
||||
// test for attribute type
|
||||
if (colon > matchStart) {
|
||||
ber.encodeOctetString(filter,
|
||||
LDAP_FILTER_EXT_TYPE, matchStart, colon - matchStart);
|
||||
}
|
||||
} else {
|
||||
ber.encodeOctetString(filter, LDAP_FILTER_EXT_TYPE, matchStart,
|
||||
matchEnd - matchStart);
|
||||
}
|
||||
|
||||
ber.encodeOctetString(
|
||||
unescapeFilterValue(filter, valueStart, valueEnd),
|
||||
LDAP_FILTER_EXT_VAL);
|
||||
|
||||
/*
|
||||
* This element is defined in RFC-2251 with an ASN.1 DEFAULT tag.
|
||||
* However, for Active Directory interoperability it is transmitted
|
||||
* even when FALSE.
|
||||
*/
|
||||
ber.encodeBoolean(matchDN, LDAP_FILTER_EXT_DN);
|
||||
|
||||
ber.endSeq();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// some debug print code that does indenting. Useful for debugging
|
||||
// the filter generation code
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private static final boolean dbg = false;
|
||||
private static int dbgIndent = 0;
|
||||
|
||||
private static void dprint(String msg) {
|
||||
dprint(msg, new byte[0], 0, 0);
|
||||
}
|
||||
|
||||
private static void dprint(String msg, byte[] str) {
|
||||
dprint(msg, str, 0, str.length);
|
||||
}
|
||||
|
||||
private static void dprint(String msg, byte[] str, int start, int end) {
|
||||
String dstr = " ";
|
||||
int i = dbgIndent;
|
||||
while (i-- > 0) {
|
||||
dstr += " ";
|
||||
}
|
||||
dstr += msg;
|
||||
|
||||
System.err.print(dstr);
|
||||
for (int j = start; j < end; j++) {
|
||||
System.err.print((char)str[j]);
|
||||
}
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
/////////////// Constants used for encoding filter //////////////
|
||||
|
||||
static final int LDAP_FILTER_AND = 0xa0;
|
||||
static final int LDAP_FILTER_OR = 0xa1;
|
||||
static final int LDAP_FILTER_NOT = 0xa2;
|
||||
static final int LDAP_FILTER_EQUALITY = 0xa3;
|
||||
static final int LDAP_FILTER_SUBSTRINGS = 0xa4;
|
||||
static final int LDAP_FILTER_GE = 0xa5;
|
||||
static final int LDAP_FILTER_LE = 0xa6;
|
||||
static final int LDAP_FILTER_PRESENT = 0x87;
|
||||
static final int LDAP_FILTER_APPROX = 0xa8;
|
||||
static final int LDAP_FILTER_EXT = 0xa9; // LDAPv3
|
||||
|
||||
static final int LDAP_FILTER_EXT_RULE = 0x81; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_TYPE = 0x82; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_VAL = 0x83; // LDAPv3
|
||||
static final int LDAP_FILTER_EXT_DN = 0x84; // LDAPv3
|
||||
|
||||
static final int LDAP_SUBSTRING_INITIAL = 0x80;
|
||||
static final int LDAP_SUBSTRING_ANY = 0x81;
|
||||
static final int LDAP_SUBSTRING_FINAL = 0x82;
|
||||
}
|
||||
212
jdkSrc/jdk8/com/sun/jndi/ldap/LdapAttribute.java
Normal file
212
jdkSrc/jdk8/com/sun/jndi/ldap/LdapAttribute.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
/**
|
||||
* This subclass is used by LDAP to implement the schema calls.
|
||||
* Basically, it keeps track of which context it is an attribute of
|
||||
* so it can get the schema for that cotnext.
|
||||
*
|
||||
* @author Jon Ruiz
|
||||
*/
|
||||
final class LdapAttribute extends BasicAttribute {
|
||||
|
||||
static final long serialVersionUID = -4288716561020779584L;
|
||||
|
||||
private transient DirContext baseCtx = null;
|
||||
private Name rdn = new CompositeName();
|
||||
|
||||
// these two are used to reconstruct the baseCtx if this attribute has
|
||||
// been serialized (
|
||||
private String baseCtxURL;
|
||||
private Hashtable<String, ? super String> baseCtxEnv;
|
||||
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
public Object clone() {
|
||||
LdapAttribute attr = new LdapAttribute(this.attrID, baseCtx, rdn);
|
||||
attr.values = (Vector<Object>)values.clone();
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new value to this attribute.
|
||||
*
|
||||
* @param attrVal The value to be added. If null, a null value is added to
|
||||
* the attribute.
|
||||
* @return true Always returns true.
|
||||
*/
|
||||
public boolean add(Object attrVal) {
|
||||
// LDAP attributes don't contain duplicate values so there's no need
|
||||
// to check if the value already exists before adding it.
|
||||
values.addElement(attrVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of an attribute.
|
||||
*
|
||||
* @param id The attribute's id. It cannot be null.
|
||||
*/
|
||||
LdapAttribute(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of an attribute.
|
||||
*
|
||||
* @param id The attribute's id. It cannot be null.
|
||||
* @param baseCtx the baseCtx object of this attribute
|
||||
* @param rdn the RDN of the entry (relative to baseCtx)
|
||||
*/
|
||||
private LdapAttribute(String id, DirContext baseCtx, Name rdn) {
|
||||
super(id);
|
||||
this.baseCtx = baseCtx;
|
||||
this.rdn = rdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the baseCtx and rdn used to find the attribute's schema
|
||||
* Used by LdapCtx.setParents().
|
||||
*/
|
||||
void setParent(DirContext baseCtx, Name rdn) {
|
||||
this.baseCtx = baseCtx;
|
||||
this.rdn = rdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the ctx this attribute came from. This call allows
|
||||
* LDAPAttribute to be serializable. 'baseCtx' is transient so if
|
||||
* it is null, the `baseCtxURL` is used to reconstruct the context
|
||||
* to which calls are made.
|
||||
*/
|
||||
private DirContext getBaseCtx() throws NamingException {
|
||||
if(baseCtx == null) {
|
||||
if (baseCtxEnv == null) {
|
||||
baseCtxEnv = new Hashtable<String, String>(3);
|
||||
}
|
||||
baseCtxEnv.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.ldap.LdapCtxFactory");
|
||||
baseCtxEnv.put(Context.PROVIDER_URL,baseCtxURL);
|
||||
baseCtx = (new InitialDirContext(baseCtxEnv));
|
||||
}
|
||||
return baseCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the object is serialized. It is
|
||||
* overridden so that the appropriate class variables can be set
|
||||
* to re-construct the baseCtx when deserialized. Setting these
|
||||
* variables is costly, so it is only done if the object
|
||||
* is actually serialized.
|
||||
*/
|
||||
private void writeObject(java.io.ObjectOutputStream out)
|
||||
throws IOException {
|
||||
|
||||
// setup internal state
|
||||
this.setBaseCtxInfo();
|
||||
|
||||
// let the ObjectOutpurStream do the real work of serialization
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the information needed to reconstruct the baseCtx if
|
||||
* we are serialized. This must be called _before_ the object is
|
||||
* serialized!!!
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
private void setBaseCtxInfo() {
|
||||
Hashtable<String, Object> realEnv = null;
|
||||
Hashtable<String, Object> secureEnv = null;
|
||||
|
||||
if (baseCtx != null) {
|
||||
realEnv = ((LdapCtx)baseCtx).envprops;
|
||||
this.baseCtxURL = ((LdapCtx)baseCtx).getURL();
|
||||
}
|
||||
|
||||
if(realEnv != null && realEnv.size() > 0 ) {
|
||||
// remove any security credentials - otherwise the serialized form
|
||||
// would store them in the clear
|
||||
for (String key : realEnv.keySet()){
|
||||
if (key.indexOf("security") != -1 ) {
|
||||
|
||||
//if we need to remove props, we must do it to a clone
|
||||
//of the environment. cloning is expensive, so we only do
|
||||
//it if we have to.
|
||||
if(secureEnv == null) {
|
||||
secureEnv = (Hashtable<String, Object>)realEnv.clone();
|
||||
}
|
||||
secureEnv.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set baseCtxEnv depending on whether we removed props or not
|
||||
this.baseCtxEnv = (secureEnv == null ? realEnv : secureEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the syntax definition associated with this attribute.
|
||||
* @return This attribute's syntax definition.
|
||||
*/
|
||||
public DirContext getAttributeSyntaxDefinition() throws NamingException {
|
||||
// get the syntax id from the attribute def
|
||||
DirContext schema = getBaseCtx().getSchema(rdn);
|
||||
DirContext attrDef = (DirContext)schema.lookup(
|
||||
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());
|
||||
|
||||
Attribute syntaxAttr = attrDef.getAttributes("").get("SYNTAX");
|
||||
|
||||
if(syntaxAttr == null || syntaxAttr.size() == 0) {
|
||||
throw new NameNotFoundException(
|
||||
getID() + "does not have a syntax associated with it");
|
||||
}
|
||||
|
||||
String syntaxName = (String)syntaxAttr.get();
|
||||
|
||||
// look in the schema tree for the syntax definition
|
||||
return (DirContext)schema.lookup(
|
||||
LdapSchemaParser.SYNTAX_DEFINITION_NAME + "/" + syntaxName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this attribute's schema definition.
|
||||
*
|
||||
* @return This attribute's schema definition.
|
||||
*/
|
||||
public DirContext getAttributeDefinition() throws NamingException {
|
||||
DirContext schema = getBaseCtx().getSchema(rdn);
|
||||
|
||||
return (DirContext)schema.lookup(
|
||||
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());
|
||||
}
|
||||
}
|
||||
112
jdkSrc/jdk8/com/sun/jndi/ldap/LdapBindingEnumeration.java
Normal file
112
jdkSrc/jdk8/com/sun/jndi/ldap/LdapBindingEnumeration.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.spi.*;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
final class LdapBindingEnumeration
|
||||
extends AbstractLdapNamingEnumeration<Binding> {
|
||||
|
||||
private final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
LdapBindingEnumeration(LdapCtx homeCtx, LdapResult answer, Name remain,
|
||||
Continuation cont) throws NamingException
|
||||
{
|
||||
super(homeCtx, answer, remain, cont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Binding
|
||||
createItem(String dn, Attributes attrs, Vector<Control> respCtls)
|
||||
throws NamingException {
|
||||
|
||||
Object obj = null;
|
||||
String atom = getAtom(dn);
|
||||
|
||||
if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
|
||||
// serialized object or object reference
|
||||
try {
|
||||
obj = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@Override
|
||||
public Object run() throws NamingException {
|
||||
return Obj.decodeObject(attrs);
|
||||
}
|
||||
}, acc);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (NamingException)e.getException();
|
||||
}
|
||||
}
|
||||
if (obj == null) {
|
||||
// DirContext object
|
||||
obj = new LdapCtx(homeCtx, dn);
|
||||
}
|
||||
|
||||
CompositeName cn = new CompositeName();
|
||||
cn.add(atom);
|
||||
|
||||
try {
|
||||
obj = DirectoryManager.getObjectInstance(obj, cn, homeCtx,
|
||||
homeCtx.envprops, attrs);
|
||||
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
|
||||
} catch (Exception e) {
|
||||
NamingException ne =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
Binding binding;
|
||||
if (respCtls != null) {
|
||||
binding = new BindingWithControls(cn.toString(), obj,
|
||||
homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
binding = new Binding(cn.toString(), obj);
|
||||
}
|
||||
binding.setNameInNamespace(dn);
|
||||
return binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException{
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.listBindings(listArg);
|
||||
}
|
||||
}
|
||||
1618
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClient.java
Normal file
1618
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClient.java
Normal file
File diff suppressed because it is too large
Load Diff
71
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClientFactory.java
Normal file
71
jdkSrc/jdk8/com/sun/jndi/ldap/LdapClientFactory.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2005, 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.ldap;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import com.sun.jndi.ldap.pool.PoolCallback;
|
||||
import com.sun.jndi.ldap.pool.PooledConnection;
|
||||
import com.sun.jndi.ldap.pool.PooledConnectionFactory;
|
||||
|
||||
/**
|
||||
* Creates an LdapClient. Encapsulates the parameters required to create
|
||||
* an LdapClient and provides methods for returning appropriate exceptions
|
||||
* to throw when acquiring a pooled LdapClient fails.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class LdapClientFactory implements PooledConnectionFactory {
|
||||
final private String host;
|
||||
final private int port;
|
||||
final private String socketFactory;
|
||||
final private int connTimeout;
|
||||
final private int readTimeout;
|
||||
final private OutputStream trace;
|
||||
|
||||
LdapClientFactory(String host, int port, String socketFactory,
|
||||
int connTimeout, int readTimeout, OutputStream trace) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.socketFactory = socketFactory;
|
||||
this.connTimeout = connTimeout;
|
||||
this.readTimeout = readTimeout;
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public PooledConnection createPooledConnection(PoolCallback pcb)
|
||||
throws NamingException {
|
||||
return new LdapClient(host, port, socketFactory,
|
||||
connTimeout, readTimeout, trace, pcb);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return host + ":" + port;
|
||||
}
|
||||
}
|
||||
3716
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtx.java
Normal file
3716
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtx.java
Normal file
File diff suppressed because it is too large
Load Diff
303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtxFactory.java
Normal file
303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapCtxFactory.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2018, 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.ldap;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
import javax.naming.spi.InitialContextFactory;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import com.sun.jndi.url.ldap.ldapURLContextFactory;
|
||||
|
||||
final public class LdapCtxFactory implements ObjectFactory, InitialContextFactory {
|
||||
/**
|
||||
* The type of each address in an LDAP reference.
|
||||
*/
|
||||
public final static String ADDRESS_TYPE = "URL";
|
||||
|
||||
// ----------------- ObjectFactory interface --------------------
|
||||
|
||||
public Object getObjectInstance(Object ref, Name name, Context nameCtx,
|
||||
Hashtable<?,?> env) throws Exception {
|
||||
|
||||
if (!isLdapRef(ref)) {
|
||||
return null;
|
||||
}
|
||||
ObjectFactory factory = new ldapURLContextFactory();
|
||||
String[] urls = getURLs((Reference)ref);
|
||||
return factory.getObjectInstance(urls, name, nameCtx, env);
|
||||
}
|
||||
|
||||
// ----------------- InitialContext interface --------------------
|
||||
|
||||
public Context getInitialContext(Hashtable<?,?> envprops)
|
||||
throws NamingException {
|
||||
|
||||
try {
|
||||
String providerUrl = (envprops != null) ?
|
||||
(String)envprops.get(Context.PROVIDER_URL) : null;
|
||||
|
||||
// If URL not in environment, use defaults
|
||||
if (providerUrl == null) {
|
||||
return new LdapCtx("", LdapCtx.DEFAULT_HOST,
|
||||
LdapCtx.DEFAULT_PORT, envprops, false);
|
||||
}
|
||||
|
||||
// Extract URL(s)
|
||||
String[] urls = LdapURL.fromList(providerUrl);
|
||||
|
||||
if (urls.length == 0) {
|
||||
throw new ConfigurationException(Context.PROVIDER_URL +
|
||||
" property does not contain a URL");
|
||||
}
|
||||
|
||||
// Generate an LDAP context
|
||||
return getLdapCtxInstance(urls, envprops);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
if (envprops != null &&
|
||||
"throw".equals(envprops.get(Context.REFERRAL))) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
Control[] bindCtls = (envprops != null)?
|
||||
(Control[])envprops.get(LdapCtx.BIND_CONTROLS) : null;
|
||||
|
||||
return (LdapCtx)e.getReferralContext(envprops, bindCtls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if argument is an LDAP reference.
|
||||
*/
|
||||
private static boolean isLdapRef(Object obj) {
|
||||
|
||||
if (!(obj instanceof Reference)) {
|
||||
return false;
|
||||
}
|
||||
String thisClassName = LdapCtxFactory.class.getName();
|
||||
Reference ref = (Reference)obj;
|
||||
|
||||
return thisClassName.equals(ref.getFactoryClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URLs contained within an LDAP reference.
|
||||
*/
|
||||
private static String[] getURLs(Reference ref) throws NamingException {
|
||||
|
||||
int size = 0; // number of URLs
|
||||
String[] urls = new String[ref.size()];
|
||||
|
||||
Enumeration<RefAddr> addrs = ref.getAll();
|
||||
while (addrs.hasMoreElements()) {
|
||||
RefAddr addr = addrs.nextElement();
|
||||
|
||||
if ((addr instanceof StringRefAddr) &&
|
||||
addr.getType().equals(ADDRESS_TYPE)) {
|
||||
|
||||
urls[size++] = (String)addr.getContent();
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
throw (new ConfigurationException(
|
||||
"Reference contains no valid addresses"));
|
||||
}
|
||||
|
||||
// Trim URL array down to size.
|
||||
if (size == ref.size()) {
|
||||
return urls;
|
||||
}
|
||||
String[] urls2 = new String[size];
|
||||
System.arraycopy(urls, 0, urls2, 0, size);
|
||||
return urls2;
|
||||
}
|
||||
|
||||
// ------------ Utilities used by other classes ----------------
|
||||
|
||||
public static DirContext getLdapCtxInstance(Object urlInfo, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
if (urlInfo instanceof String) {
|
||||
return getUsingURL((String)urlInfo, env);
|
||||
} else if (urlInfo instanceof String[]) {
|
||||
return getUsingURLs((String[])urlInfo, env);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"argument must be an LDAP URL String or array of them");
|
||||
}
|
||||
}
|
||||
|
||||
private static DirContext getUsingURL(String url, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
try {
|
||||
LdapDnsProviderResult r =
|
||||
LdapDnsProviderService.getInstance().lookupEndpoints(url, env);
|
||||
LdapCtx ctx;
|
||||
NamingException lastException = null;
|
||||
|
||||
/*
|
||||
* Prior to this change we had been assuming that the url.getDN()
|
||||
* should be converted to a domain name via
|
||||
* ServiceLocator.mapDnToDomainName(url.getDN())
|
||||
*
|
||||
* However this is incorrect as we can't assume that the supplied
|
||||
* url.getDN() is the same as the dns domain for the directory
|
||||
* server.
|
||||
*
|
||||
* This means that we depend on the dnsProvider to return both
|
||||
* the list of urls of individual hosts from which we attempt to
|
||||
* create an LdapCtx from *AND* the domain name that they serve
|
||||
*
|
||||
* In order to do this the dnsProvider must return an
|
||||
* {@link LdapDnsProviderResult}.
|
||||
*
|
||||
*/
|
||||
for (String u : r.getEndpoints()) {
|
||||
try {
|
||||
ctx = getLdapCtxFromUrl(
|
||||
r.getDomainName(), url, new LdapURL(u), env);
|
||||
return ctx;
|
||||
} catch (AuthenticationException e) {
|
||||
// do not retry on a different endpoint to avoid blocking
|
||||
// the user if authentication credentials are wrong.
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
// try the next element
|
||||
lastException = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastException != null) {
|
||||
throw lastException;
|
||||
}
|
||||
|
||||
// lookupEndpoints returned an LdapDnsProviderResult with an empty
|
||||
// list of endpoints
|
||||
throw new NamingException("Could not resolve a valid ldap host");
|
||||
} catch (NamingException e) {
|
||||
// lookupEndpoints(url, env) may throw a NamingException, which
|
||||
// there is no need to wrap.
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
NamingException ex = new NamingException();
|
||||
ex.setRootCause(e);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
private static LdapCtx getLdapCtxFromUrl(String domain,
|
||||
String url,
|
||||
LdapURL u,
|
||||
Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
String dn = u.getDN();
|
||||
String host = u.getHost();
|
||||
int port = u.getPort();
|
||||
LdapCtx ctx = new LdapCtx(dn, host, port, env, u.useSsl());
|
||||
ctx.setDomainName(domain);
|
||||
// Record the URL that created the context
|
||||
ctx.setProviderUrl(url);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try each URL until one of them succeeds.
|
||||
* If all URLs fail, throw one of the exceptions arbitrarily.
|
||||
* Not pretty, but potentially more informative than returning null.
|
||||
*/
|
||||
private static DirContext getUsingURLs(String[] urls, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
NamingException ex = null;
|
||||
for (String u : urls) {
|
||||
try {
|
||||
return getUsingURL(u, env);
|
||||
} catch (AuthenticationException e) {
|
||||
// do not retry on a different endpoint to avoid blocking
|
||||
// the user if authentication credentials are wrong.
|
||||
throw e;
|
||||
} catch (NamingException e) {
|
||||
ex = e;
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Obj and obj/RemoteToAttrs too so must be public
|
||||
*/
|
||||
public static Attribute createTypeNameAttr(Class<?> cl) {
|
||||
Vector<String> v = new Vector<>(10);
|
||||
String[] types = getTypeNames(cl, v);
|
||||
if (types.length > 0) {
|
||||
BasicAttribute tAttr =
|
||||
new BasicAttribute(Obj.JAVA_ATTRIBUTES[Obj.TYPENAME]);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
tAttr.add(types[i]);
|
||||
}
|
||||
return tAttr;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String[] getTypeNames(Class<?> currentClass, Vector<String> v) {
|
||||
|
||||
getClassesAux(currentClass, v);
|
||||
Class<?>[] members = currentClass.getInterfaces();
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
getClassesAux(members[i], v);
|
||||
}
|
||||
String[] ret = new String[v.size()];
|
||||
int i = 0;
|
||||
|
||||
for (String name : v) {
|
||||
ret[i++] = name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void getClassesAux(Class<?> currentClass, Vector<String> v) {
|
||||
if (!v.contains(currentClass.getName())) {
|
||||
v.addElement(currentClass.getName());
|
||||
}
|
||||
currentClass = currentClass.getSuperclass();
|
||||
|
||||
while (currentClass != null) {
|
||||
getTypeNames(currentClass, v);
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
jdkSrc/jdk8/com/sun/jndi/ldap/LdapDnsProviderService.java
Normal file
114
jdkSrc/jdk8/com/sun/jndi/ldap/LdapDnsProviderService.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, 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.ldap;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import javax.naming.NamingException;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProvider;
|
||||
import com.sun.jndi.ldap.spi.LdapDnsProviderResult;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
/**
|
||||
* The {@code LdapDnsProviderService} is responsible for creating and providing
|
||||
* access to the registered {@code LdapDnsProvider}s. The {@link ServiceLoader}
|
||||
* is used to find and register any implementations of {@link LdapDnsProvider}.
|
||||
*
|
||||
* <p> Instances of this class are safe for use by multiple threads.
|
||||
*/
|
||||
final class LdapDnsProviderService {
|
||||
|
||||
private static volatile LdapDnsProviderService service;
|
||||
private static final Object LOCK = new int[0];
|
||||
private final ServiceLoader<LdapDnsProvider> providers;
|
||||
|
||||
/**
|
||||
* Creates a new instance of LdapDnsProviderService
|
||||
*/
|
||||
private LdapDnsProviderService() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
providers = ServiceLoader.load(
|
||||
LdapDnsProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
} else {
|
||||
final PrivilegedAction<ServiceLoader<LdapDnsProvider>> pa =
|
||||
() -> ServiceLoader.load(
|
||||
LdapDnsProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
|
||||
providers = AccessController.doPrivileged(
|
||||
pa,
|
||||
null,
|
||||
new RuntimePermission("ldapDnsProvider"),
|
||||
SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the singleton instance of LdapDnsProviderService.
|
||||
*/
|
||||
static LdapDnsProviderService getInstance() {
|
||||
if (service != null) return service;
|
||||
synchronized (LOCK) {
|
||||
if (service != null) return service;
|
||||
service = new LdapDnsProviderService();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves result from the first provider that successfully resolves
|
||||
* the endpoints. If no results are found when calling installed
|
||||
* subclasses of {@code LdapDnsProvider} then this method will fall back
|
||||
* to the {@code DefaultLdapDnsProvider}.
|
||||
*
|
||||
* @throws NamingException if the {@code url} in not valid or an error
|
||||
* occurred while performing the lookup.
|
||||
*/
|
||||
LdapDnsProviderResult lookupEndpoints(String url, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
LdapDnsProviderResult result = null;
|
||||
Hashtable<?, ?> envCopy = new Hashtable<>(env);
|
||||
synchronized (LOCK) {
|
||||
Iterator<LdapDnsProvider> iterator = providers.iterator();
|
||||
while (result == null && iterator.hasNext()) {
|
||||
result = iterator.next().lookupEndpoints(url, envCopy)
|
||||
.filter(r -> !r.getEndpoints().isEmpty())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
return new DefaultLdapDnsProvider().lookupEndpoints(url, env)
|
||||
.orElse(new LdapDnsProviderResult("", Collections.emptyList()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
53
jdkSrc/jdk8/com/sun/jndi/ldap/LdapEntry.java
Normal file
53
jdkSrc/jdk8/com/sun/jndi/ldap/LdapEntry.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* A holder for an LDAP entry read from an LDAP server.
|
||||
*
|
||||
* @author Jagane Sundar
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final class LdapEntry {
|
||||
String DN;
|
||||
Attributes attributes;
|
||||
Vector<Control> respCtls = null;
|
||||
|
||||
LdapEntry(String DN, Attributes attrs) {
|
||||
this.DN = DN;
|
||||
this.attributes = attrs;
|
||||
}
|
||||
|
||||
LdapEntry(String DN, Attributes attrs, Vector<Control> respCtls) {
|
||||
this.DN = DN;
|
||||
this.attributes = attrs;
|
||||
this.respCtls = respCtls;
|
||||
}
|
||||
}
|
||||
1020
jdkSrc/jdk8/com/sun/jndi/ldap/LdapName.java
Normal file
1020
jdkSrc/jdk8/com/sun/jndi/ldap/LdapName.java
Normal file
File diff suppressed because it is too large
Load Diff
41
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNameParser.java
Normal file
41
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNameParser.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2003, 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.ldap;
|
||||
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
|
||||
class LdapNameParser implements NameParser {
|
||||
|
||||
public LdapNameParser() {
|
||||
}
|
||||
|
||||
public Name parse(String name) throws NamingException {
|
||||
return new LdapName(name);
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNamingEnumeration.java
Normal file
80
jdkSrc/jdk8/com/sun/jndi/ldap/LdapNamingEnumeration.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
import java.util.Vector;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
|
||||
final class LdapNamingEnumeration
|
||||
extends AbstractLdapNamingEnumeration<NameClassPair> {
|
||||
|
||||
private static final String defaultClassName = DirContext.class.getName();
|
||||
|
||||
LdapNamingEnumeration(LdapCtx homeCtx, LdapResult answer, Name listArg,
|
||||
Continuation cont) throws NamingException {
|
||||
super(homeCtx, answer, listArg, cont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NameClassPair createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls) throws NamingException {
|
||||
|
||||
Attribute attr;
|
||||
String className = null;
|
||||
|
||||
// use the Java classname if present
|
||||
if ((attr = attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME])) != null) {
|
||||
className = (String)attr.get();
|
||||
} else {
|
||||
className = defaultClassName;
|
||||
}
|
||||
CompositeName cn = new CompositeName();
|
||||
cn.add(getAtom(dn));
|
||||
|
||||
NameClassPair ncp;
|
||||
if (respCtls != null) {
|
||||
ncp = new NameClassPairWithControls(
|
||||
cn.toString(), className,
|
||||
homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
ncp = new NameClassPair(cn.toString(), className);
|
||||
}
|
||||
ncp.setNameInNamespace(dn);
|
||||
return ncp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException {
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.list(listArg);
|
||||
}
|
||||
}
|
||||
441
jdkSrc/jdk8/com/sun/jndi/ldap/LdapPoolManager.java
Normal file
441
jdkSrc/jdk8/com/sun/jndi/ldap/LdapPoolManager.java
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.naming.ldap.Control;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import com.sun.jndi.ldap.pool.PoolCleaner;
|
||||
import com.sun.jndi.ldap.pool.Pool;
|
||||
import sun.misc.InnocuousThread;
|
||||
|
||||
/**
|
||||
* Contains utilities for managing connection pools of LdapClient.
|
||||
* Contains method for
|
||||
* - checking whether attempted connection creation may be pooled
|
||||
* - creating a pooled connection
|
||||
* - closing idle connections.
|
||||
*
|
||||
* If a timeout period has been configured, then it will automatically
|
||||
* close and remove idle connections (those that have not been
|
||||
* used for the duration of the timeout period).
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
public final class LdapPoolManager {
|
||||
private static final String DEBUG =
|
||||
"com.sun.jndi.ldap.connect.pool.debug";
|
||||
|
||||
public static final boolean debug =
|
||||
"all".equalsIgnoreCase(getProperty(DEBUG, null));
|
||||
|
||||
public static final boolean trace = debug ||
|
||||
"fine".equalsIgnoreCase(getProperty(DEBUG, null));
|
||||
|
||||
// ---------- System properties for connection pooling
|
||||
|
||||
// Authentication mechanisms of connections that may be pooled
|
||||
private static final String POOL_AUTH =
|
||||
"com.sun.jndi.ldap.connect.pool.authentication";
|
||||
|
||||
// Protocol types of connections that may be pooled
|
||||
private static final String POOL_PROTOCOL =
|
||||
"com.sun.jndi.ldap.connect.pool.protocol";
|
||||
|
||||
// Maximum number of identical connections per pool
|
||||
private static final String MAX_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.maxsize";
|
||||
|
||||
// Preferred number of identical connections per pool
|
||||
private static final String PREF_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.prefsize";
|
||||
|
||||
// Initial number of identical connections per pool
|
||||
private static final String INIT_POOL_SIZE =
|
||||
"com.sun.jndi.ldap.connect.pool.initsize";
|
||||
|
||||
// Milliseconds to wait before closing idle connections
|
||||
private static final String POOL_TIMEOUT =
|
||||
"com.sun.jndi.ldap.connect.pool.timeout";
|
||||
|
||||
// Properties for DIGEST
|
||||
private static final String SASL_CALLBACK =
|
||||
"java.naming.security.sasl.callback";
|
||||
|
||||
// --------- Constants
|
||||
private static final int DEFAULT_MAX_POOL_SIZE = 0;
|
||||
private static final int DEFAULT_PREF_POOL_SIZE = 0;
|
||||
private static final int DEFAULT_INIT_POOL_SIZE = 1;
|
||||
private static final int DEFAULT_TIMEOUT = 0; // no timeout
|
||||
private static final String DEFAULT_AUTH_MECHS = "none simple";
|
||||
private static final String DEFAULT_PROTOCOLS = "plain";
|
||||
|
||||
private static final int NONE = 0; // indices into pools
|
||||
private static final int SIMPLE = 1;
|
||||
private static final int DIGEST = 2;
|
||||
|
||||
// --------- static fields
|
||||
private static final long idleTimeout;// ms to wait before closing idle conn
|
||||
private static final int maxSize; // max num of identical conns/pool
|
||||
private static final int prefSize; // preferred num of identical conns/pool
|
||||
private static final int initSize; // initial num of identical conns/pool
|
||||
|
||||
private static boolean supportPlainProtocol = false;
|
||||
private static boolean supportSslProtocol = false;
|
||||
|
||||
// List of pools used for different auth types
|
||||
private static final Pool[] pools = new Pool[3];
|
||||
|
||||
static {
|
||||
maxSize = getInteger(MAX_POOL_SIZE, DEFAULT_MAX_POOL_SIZE);
|
||||
|
||||
prefSize = getInteger(PREF_POOL_SIZE, DEFAULT_PREF_POOL_SIZE);
|
||||
|
||||
initSize = getInteger(INIT_POOL_SIZE, DEFAULT_INIT_POOL_SIZE);
|
||||
|
||||
idleTimeout = getLong(POOL_TIMEOUT, DEFAULT_TIMEOUT);
|
||||
|
||||
// Determine supported authentication mechanisms
|
||||
String str = getProperty(POOL_AUTH, DEFAULT_AUTH_MECHS);
|
||||
StringTokenizer parser = new StringTokenizer(str);
|
||||
int count = parser.countTokens();
|
||||
String mech;
|
||||
int p;
|
||||
for (int i = 0; i < count; i++) {
|
||||
mech = parser.nextToken().toLowerCase(Locale.ENGLISH);
|
||||
if (mech.equals("anonymous")) {
|
||||
mech = "none";
|
||||
}
|
||||
|
||||
p = findPool(mech);
|
||||
if (p >= 0 && pools[p] == null) {
|
||||
pools[p] = new Pool(initSize, prefSize, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine supported protocols
|
||||
str= getProperty(POOL_PROTOCOL, DEFAULT_PROTOCOLS);
|
||||
parser = new StringTokenizer(str);
|
||||
count = parser.countTokens();
|
||||
String proto;
|
||||
for (int i = 0; i < count; i++) {
|
||||
proto = parser.nextToken();
|
||||
if ("plain".equalsIgnoreCase(proto)) {
|
||||
supportPlainProtocol = true;
|
||||
} else if ("ssl".equalsIgnoreCase(proto)) {
|
||||
supportSslProtocol = true;
|
||||
} else {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (idleTimeout > 0) {
|
||||
// Create cleaner to expire idle connections
|
||||
PrivilegedAction<Void> pa = new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
Thread t = InnocuousThread.newSystemThread(
|
||||
"LDAP PoolCleaner",
|
||||
new PoolCleaner(idleTimeout, pools));
|
||||
assert t.getContextClassLoader() == null;
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
return null;
|
||||
}};
|
||||
AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
showStats(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot instantiate one of these
|
||||
private LdapPoolManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the pool for the specified mechanism. If not
|
||||
* one of "none", "simple", "DIGEST-MD5", or "GSSAPI",
|
||||
* return -1.
|
||||
* @param mech mechanism type
|
||||
*/
|
||||
private static int findPool(String mech) {
|
||||
if ("none".equalsIgnoreCase(mech)) {
|
||||
return NONE;
|
||||
} else if ("simple".equalsIgnoreCase(mech)) {
|
||||
return SIMPLE;
|
||||
} else if ("digest-md5".equalsIgnoreCase(mech)) {
|
||||
return DIGEST;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether pooling is allowed given information on how
|
||||
* the connection will be used.
|
||||
*
|
||||
* Non-configurable rejections:
|
||||
* - nonstandard socketFactory has been specified: the pool manager
|
||||
* cannot track input or parameters used by the socket factory and
|
||||
* thus has no way of determining whether two connection requests
|
||||
* are equivalent. Maybe in the future it might add a list of allowed
|
||||
* socket factories to be configured
|
||||
* - trace enabled (except when debugging)
|
||||
* - for Digest authentication, if a callback handler has been specified:
|
||||
* the pool manager cannot track input collected by the handler
|
||||
* and thus has no way of determining whether two connection requests are
|
||||
* equivalent. Maybe in the future it might add a list of allowed
|
||||
* callback handlers.
|
||||
*
|
||||
* Configurable tests:
|
||||
* - Pooling for the requested protocol (plain or ssl) is supported
|
||||
* - Pooling for the requested authentication mechanism is supported
|
||||
*
|
||||
*/
|
||||
static boolean isPoolingAllowed(String socketFactory, OutputStream trace,
|
||||
String authMech, String protocol, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
if (trace != null && !debug
|
||||
|
||||
// Requesting plain protocol but it is not supported
|
||||
|| (protocol == null && !supportPlainProtocol)
|
||||
|
||||
// Requesting ssl protocol but it is not supported
|
||||
|| ("ssl".equalsIgnoreCase(protocol) && !supportSslProtocol)) {
|
||||
|
||||
d("Pooling disallowed due to tracing or unsupported pooling of protocol");
|
||||
return false;
|
||||
}
|
||||
// pooling of custom socket factory is possible only if the
|
||||
// socket factory interface implements java.util.comparator
|
||||
String COMPARATOR = "java.util.Comparator";
|
||||
boolean foundSockCmp = false;
|
||||
if ((socketFactory != null) &&
|
||||
!socketFactory.equals(LdapCtx.DEFAULT_SSL_FACTORY)) {
|
||||
try {
|
||||
Class<?> socketFactoryClass = Obj.helper.loadClass(socketFactory);
|
||||
Class<?>[] interfaces = socketFactoryClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
if (interfaces[i].getCanonicalName().equals(COMPARATOR)) {
|
||||
foundSockCmp = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CommunicationException ce =
|
||||
new CommunicationException("Loading the socket factory");
|
||||
ce.setRootCause(e);
|
||||
throw ce;
|
||||
}
|
||||
if (!foundSockCmp) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Cannot use pooling if authMech is not a supported mechs
|
||||
// Cannot use pooling if authMech contains multiple mechs
|
||||
int p = findPool(authMech);
|
||||
if (p < 0 || pools[p] == null) {
|
||||
d("authmech not found: ", authMech);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
d("using authmech: ", authMech);
|
||||
|
||||
switch (p) {
|
||||
case NONE:
|
||||
case SIMPLE:
|
||||
return true;
|
||||
|
||||
case DIGEST:
|
||||
// Provider won't be able to determine connection identity
|
||||
// if an alternate callback handler is used
|
||||
return (env == null || env.get(SASL_CALLBACK) == null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a pooled connection that either already exists or is
|
||||
* newly created using the parameters supplied. If it is newly
|
||||
* created, it needs to go through the authentication checks to
|
||||
* determine whether an LDAP bind is necessary.
|
||||
*
|
||||
* Caller needs to invoke ldapClient.authenticateCalled() to
|
||||
* determine whether ldapClient.authenticate() needs to be invoked.
|
||||
* Caller has that responsibility because caller needs to deal
|
||||
* with the LDAP bind response, which might involve referrals,
|
||||
* response controls, errors, etc. This method is responsible only
|
||||
* for establishing the connection.
|
||||
*
|
||||
* @return an LdapClient that is pooled.
|
||||
*/
|
||||
static LdapClient getLdapClient(String host, int port, String socketFactory,
|
||||
int connTimeout, int readTimeout, OutputStream trace, int version,
|
||||
String authMech, Control[] ctls, String protocol, String user,
|
||||
Object passwd, Hashtable<?,?> env) throws NamingException {
|
||||
|
||||
// Create base identity for LdapClient
|
||||
ClientId id = null;
|
||||
Pool pool;
|
||||
|
||||
int p = findPool(authMech);
|
||||
if (p < 0 || (pool=pools[p]) == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Attempting to use pooling for an unsupported mechanism: " +
|
||||
authMech);
|
||||
}
|
||||
switch (p) {
|
||||
case NONE:
|
||||
id = new ClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory);
|
||||
break;
|
||||
|
||||
case SIMPLE:
|
||||
// Add identity information used in simple authentication
|
||||
id = new SimpleClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory, user, passwd);
|
||||
break;
|
||||
|
||||
case DIGEST:
|
||||
// Add user/passwd/realm/authzid/qop/strength/maxbuf/mutual/policy*
|
||||
id = new DigestClientId(version, host, port, protocol,
|
||||
ctls, trace, socketFactory, user, passwd, env);
|
||||
break;
|
||||
}
|
||||
|
||||
return (LdapClient) pool.getPooledConnection(id, connTimeout,
|
||||
new LdapClientFactory(host, port, socketFactory, connTimeout,
|
||||
readTimeout, trace));
|
||||
}
|
||||
|
||||
public static void showStats(PrintStream out) {
|
||||
out.println("***** start *****");
|
||||
out.println("idle timeout: " + idleTimeout);
|
||||
out.println("maximum pool size: " + maxSize);
|
||||
out.println("preferred pool size: " + prefSize);
|
||||
out.println("initial pool size: " + initSize);
|
||||
out.println("protocol types: " + (supportPlainProtocol ? "plain " : "") +
|
||||
(supportSslProtocol ? "ssl" : ""));
|
||||
out.println("authentication types: " +
|
||||
(pools[NONE] != null ? "none " : "") +
|
||||
(pools[SIMPLE] != null ? "simple " : "") +
|
||||
(pools[DIGEST] != null ? "DIGEST-MD5 " : ""));
|
||||
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
out.println(
|
||||
(i == NONE ? "anonymous pools" :
|
||||
i == SIMPLE ? "simple auth pools" :
|
||||
i == DIGEST ? "digest pools" : "")
|
||||
+ ":");
|
||||
pools[i].showStats(out);
|
||||
}
|
||||
}
|
||||
out.println("***** end *****");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes idle connections idle since specified time.
|
||||
*
|
||||
* @param threshold Close connections idle since this time, as
|
||||
* specified in milliseconds since "the epoch".
|
||||
* @see java.util.Date
|
||||
*/
|
||||
public static void expire(long threshold) {
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
pools[i].expire(threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println("LdapPoolManager: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void d(String msg, String o) {
|
||||
if (debug) {
|
||||
System.err.println("LdapPoolManager: " + msg + o);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String getProperty(final String propName,
|
||||
final String defVal) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
try {
|
||||
return System.getProperty(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return defVal;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final int getInteger(final String propName,
|
||||
final int defVal) {
|
||||
Integer val = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Integer>() {
|
||||
public Integer run() {
|
||||
try {
|
||||
return Integer.getInteger(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return new Integer(defVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
return val.intValue();
|
||||
}
|
||||
|
||||
private static final long getLong(final String propName,
|
||||
final long defVal) {
|
||||
Long val = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Long>() {
|
||||
public Long run() {
|
||||
try {
|
||||
return Long.getLong(propName, defVal);
|
||||
} catch (SecurityException e) {
|
||||
return new Long(defVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
return val.longValue();
|
||||
}
|
||||
}
|
||||
953
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralContext.java
Normal file
953
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralContext.java
Normal file
@@ -0,0 +1,953 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
import com.sun.jndi.toolkit.dir.SearchFilter;
|
||||
|
||||
/**
|
||||
* A context for handling referrals.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final class LdapReferralContext implements DirContext, LdapContext {
|
||||
|
||||
private DirContext refCtx = null;
|
||||
private Name urlName = null; // override the supplied name
|
||||
private String urlAttrs = null; // override attributes
|
||||
private String urlScope = null; // override scope
|
||||
private String urlFilter = null; // override filter
|
||||
|
||||
private LdapReferralException refEx = null;
|
||||
private boolean skipThisReferral = false;
|
||||
private int hopCount = 1;
|
||||
private NamingException previousEx = null;
|
||||
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
LdapReferralContext(LdapReferralException ex,
|
||||
Hashtable<?,?> env,
|
||||
Control[] connCtls,
|
||||
Control[] reqCtls,
|
||||
String nextName,
|
||||
boolean skipThisReferral,
|
||||
int handleReferrals) throws NamingException {
|
||||
|
||||
refEx = ex;
|
||||
|
||||
if (this.skipThisReferral = skipThisReferral) {
|
||||
return; // don't create a DirContext for this referral
|
||||
}
|
||||
|
||||
String referral;
|
||||
|
||||
// Make copies of environment and connect controls for our own use.
|
||||
if (env != null) {
|
||||
env = (Hashtable<?,?>) env.clone();
|
||||
// Remove old connect controls from environment, unless we have new
|
||||
// ones that will override them anyway.
|
||||
if (connCtls == null) {
|
||||
env.remove(LdapCtx.BIND_CONTROLS);
|
||||
}
|
||||
} else if (connCtls != null) {
|
||||
env = new Hashtable<String, Control[]>(5);
|
||||
}
|
||||
if (connCtls != null) {
|
||||
Control[] copiedCtls = new Control[connCtls.length];
|
||||
System.arraycopy(connCtls, 0, copiedCtls, 0, connCtls.length);
|
||||
// Add copied controls to environment, replacing any old ones.
|
||||
((Hashtable<? super String, ? super Control[]>)env)
|
||||
.put(LdapCtx.BIND_CONTROLS, copiedCtls);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
referral = refEx.getNextReferral();
|
||||
if (referral == null) {
|
||||
if (previousEx != null) {
|
||||
throw (NamingException)(previousEx.fillInStackTrace());
|
||||
} else {
|
||||
throw new NamingException(
|
||||
"Illegal encoding: referral is empty");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
if (handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw e;
|
||||
} else {
|
||||
refEx = e;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Reference containing the referral URL.
|
||||
Reference ref = new Reference("javax.naming.directory.DirContext",
|
||||
new StringRefAddr("URL", referral));
|
||||
|
||||
Object obj;
|
||||
try {
|
||||
obj = NamingManager.getObjectInstance(ref, null, null, env);
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
if (handleReferrals == LdapClient.LDAP_REF_THROW) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
// mask the exception and save it for later
|
||||
previousEx = e;
|
||||
|
||||
// follow another referral
|
||||
continue;
|
||||
|
||||
} catch (Exception e) {
|
||||
NamingException e2 =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
e2.setRootCause(e);
|
||||
throw e2;
|
||||
}
|
||||
if (obj instanceof DirContext) {
|
||||
refCtx = (DirContext)obj;
|
||||
if (refCtx instanceof LdapContext && reqCtls != null) {
|
||||
((LdapContext)refCtx).setRequestControls(reqCtls);
|
||||
}
|
||||
initDefaults(referral, nextName);
|
||||
|
||||
break;
|
||||
} else {
|
||||
NamingException ne = new NotContextException(
|
||||
"Cannot create context for: " + referral);
|
||||
ne.setRemainingName((new CompositeName()).add(nextName));
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initDefaults(String referral, String nextName)
|
||||
throws NamingException {
|
||||
String urlString;
|
||||
try {
|
||||
// parse URL
|
||||
LdapURL url = new LdapURL(referral);
|
||||
urlString = url.getDN();
|
||||
urlAttrs = url.getAttributes();
|
||||
urlScope = url.getScope();
|
||||
urlFilter = url.getFilter();
|
||||
|
||||
} catch (NamingException e) {
|
||||
// Not an LDAP URL; use original URL
|
||||
urlString = referral;
|
||||
urlAttrs = urlScope = urlFilter = null;
|
||||
}
|
||||
|
||||
// reuse original name if URL DN is absent
|
||||
if (urlString == null) {
|
||||
urlString = nextName;
|
||||
} else {
|
||||
// concatenate with remaining name if URL DN is present
|
||||
urlString = "";
|
||||
}
|
||||
|
||||
if (urlString == null) {
|
||||
urlName = null;
|
||||
} else {
|
||||
urlName = urlString.equals("") ? new CompositeName() :
|
||||
new CompositeName().add(urlString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void close() throws NamingException {
|
||||
if (refCtx != null) {
|
||||
refCtx.close();
|
||||
refCtx = null;
|
||||
}
|
||||
refEx = null;
|
||||
}
|
||||
|
||||
void setHopCount(int hopCount) {
|
||||
this.hopCount = hopCount;
|
||||
if ((refCtx != null) && (refCtx instanceof LdapCtx)) {
|
||||
((LdapCtx)refCtx).setHopCount(hopCount);
|
||||
}
|
||||
}
|
||||
|
||||
public Object lookup(String name) throws NamingException {
|
||||
return lookup(toName(name));
|
||||
}
|
||||
|
||||
public Object lookup(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.lookup(overrideName(name));
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj) throws NamingException {
|
||||
bind(toName(name), obj);
|
||||
}
|
||||
|
||||
public void bind(Name name, Object obj) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.bind(overrideName(name), obj);
|
||||
}
|
||||
|
||||
public void rebind(String name, Object obj) throws NamingException {
|
||||
rebind(toName(name), obj);
|
||||
}
|
||||
|
||||
public void rebind(Name name, Object obj) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rebind(overrideName(name), obj);
|
||||
}
|
||||
|
||||
public void unbind(String name) throws NamingException {
|
||||
unbind(toName(name));
|
||||
}
|
||||
|
||||
public void unbind(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.unbind(overrideName(name));
|
||||
}
|
||||
|
||||
public void rename(String oldName, String newName) throws NamingException {
|
||||
rename(toName(oldName), toName(newName));
|
||||
}
|
||||
|
||||
public void rename(Name oldName, Name newName) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rename(overrideName(oldName), toName(refEx.getNewRdn()));
|
||||
}
|
||||
|
||||
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
|
||||
return list(toName(name));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
try {
|
||||
NamingEnumeration<NameClassPair> ne = null;
|
||||
|
||||
if (urlScope != null && urlScope.equals("base")) {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningObjFlag(true);
|
||||
cons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
|
||||
ne = (NamingEnumeration)
|
||||
refCtx.search(overrideName(name), "(objectclass=*)", cons);
|
||||
|
||||
} else {
|
||||
ne = refCtx.list(overrideName(name));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)ne).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (ne);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<Binding> listBindings(String name) throws
|
||||
NamingException {
|
||||
return listBindings(toName(name));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public NamingEnumeration<Binding> listBindings(Name name) throws
|
||||
NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<Binding> be = null;
|
||||
|
||||
if (urlScope != null && urlScope.equals("base")) {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningObjFlag(true);
|
||||
cons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
|
||||
be = (NamingEnumeration)refCtx.search(overrideName(name),
|
||||
"(objectclass=*)", cons);
|
||||
|
||||
} else {
|
||||
be = refCtx.listBindings(overrideName(name));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration<Binding>)be).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (be);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroySubcontext(String name) throws NamingException {
|
||||
destroySubcontext(toName(name));
|
||||
}
|
||||
|
||||
public void destroySubcontext(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.destroySubcontext(overrideName(name));
|
||||
}
|
||||
|
||||
public Context createSubcontext(String name) throws NamingException {
|
||||
return createSubcontext(toName(name));
|
||||
}
|
||||
|
||||
public Context createSubcontext(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.createSubcontext(overrideName(name));
|
||||
}
|
||||
|
||||
public Object lookupLink(String name) throws NamingException {
|
||||
return lookupLink(toName(name));
|
||||
}
|
||||
|
||||
public Object lookupLink(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.lookupLink(overrideName(name));
|
||||
}
|
||||
|
||||
public NameParser getNameParser(String name) throws NamingException {
|
||||
return getNameParser(toName(name));
|
||||
}
|
||||
|
||||
public NameParser getNameParser(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getNameParser(overrideName(name));
|
||||
}
|
||||
|
||||
public String composeName(String name, String prefix)
|
||||
throws NamingException {
|
||||
return composeName(toName(name), toName(prefix)).toString();
|
||||
}
|
||||
|
||||
public Name composeName(Name name, Name prefix) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
return refCtx.composeName(name, prefix);
|
||||
}
|
||||
|
||||
public Object addToEnvironment(String propName, Object propVal)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.addToEnvironment(propName, propVal);
|
||||
}
|
||||
|
||||
public Object removeFromEnvironment(String propName)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.removeFromEnvironment(propName);
|
||||
}
|
||||
|
||||
public Hashtable<?,?> getEnvironment() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getEnvironment();
|
||||
}
|
||||
|
||||
public Attributes getAttributes(String name) throws NamingException {
|
||||
return getAttributes(toName(name));
|
||||
}
|
||||
|
||||
public Attributes getAttributes(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getAttributes(overrideName(name));
|
||||
}
|
||||
|
||||
public Attributes getAttributes(String name, String[] attrIds)
|
||||
throws NamingException {
|
||||
return getAttributes(toName(name), attrIds);
|
||||
}
|
||||
|
||||
public Attributes getAttributes(Name name, String[] attrIds)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getAttributes(overrideName(name), attrIds);
|
||||
}
|
||||
|
||||
public void modifyAttributes(String name, int mod_op, Attributes attrs)
|
||||
throws NamingException {
|
||||
modifyAttributes(toName(name), mod_op, attrs);
|
||||
}
|
||||
|
||||
public void modifyAttributes(Name name, int mod_op, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.modifyAttributes(overrideName(name), mod_op, attrs);
|
||||
}
|
||||
|
||||
public void modifyAttributes(String name, ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
modifyAttributes(toName(name), mods);
|
||||
}
|
||||
|
||||
public void modifyAttributes(Name name, ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.modifyAttributes(overrideName(name), mods);
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
bind(toName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void bind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.bind(overrideName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void rebind(String name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
rebind(toName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public void rebind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
refCtx.rebind(overrideName(name), obj, attrs);
|
||||
}
|
||||
|
||||
public DirContext createSubcontext(String name, Attributes attrs)
|
||||
throws NamingException {
|
||||
return createSubcontext(toName(name), attrs);
|
||||
}
|
||||
|
||||
public DirContext createSubcontext(Name name, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.createSubcontext(overrideName(name), attrs);
|
||||
}
|
||||
|
||||
public DirContext getSchema(String name) throws NamingException {
|
||||
return getSchema(toName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchema(Name name) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getSchema(overrideName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchemaClassDefinition(String name)
|
||||
throws NamingException {
|
||||
return getSchemaClassDefinition(toName(name));
|
||||
}
|
||||
|
||||
public DirContext getSchemaClassDefinition(Name name)
|
||||
throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
return refCtx.getSchemaClassDefinition(overrideName(name));
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
Attributes matchingAttributes)
|
||||
throws NamingException {
|
||||
return search(toName(name), SearchFilter.format(matchingAttributes),
|
||||
new SearchControls());
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
Attributes matchingAttributes)
|
||||
throws NamingException {
|
||||
return search(name, SearchFilter.format(matchingAttributes),
|
||||
new SearchControls());
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
Attributes matchingAttributes,
|
||||
String[] attributesToReturn)
|
||||
throws NamingException {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningAttributes(attributesToReturn);
|
||||
|
||||
return search(toName(name), SearchFilter.format(matchingAttributes),
|
||||
cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
Attributes matchingAttributes,
|
||||
String[] attributesToReturn)
|
||||
throws NamingException {
|
||||
SearchControls cons = new SearchControls();
|
||||
cons.setReturningAttributes(attributesToReturn);
|
||||
|
||||
return search(name, SearchFilter.format(matchingAttributes), cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
String filter,
|
||||
SearchControls cons)
|
||||
throws NamingException {
|
||||
return search(toName(name), filter, cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
String filter,
|
||||
SearchControls cons) throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<SearchResult> se =
|
||||
refCtx.search(overrideName(name),
|
||||
overrideFilter(filter),
|
||||
overrideAttributesAndScope(cons));
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (se);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// %%% VR - setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(String name,
|
||||
String filterExpr,
|
||||
Object[] filterArgs,
|
||||
SearchControls cons)
|
||||
throws NamingException {
|
||||
return search(toName(name), filterExpr, filterArgs, cons);
|
||||
}
|
||||
|
||||
public NamingEnumeration<SearchResult> search(Name name,
|
||||
String filterExpr,
|
||||
Object[] filterArgs,
|
||||
SearchControls cons) throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
try {
|
||||
NamingEnumeration<SearchResult> se;
|
||||
|
||||
if (urlFilter != null) {
|
||||
se = refCtx.search(overrideName(name), urlFilter,
|
||||
overrideAttributesAndScope(cons));
|
||||
} else {
|
||||
se = refCtx.search(overrideName(name), filterExpr,
|
||||
filterArgs, overrideAttributesAndScope(cons));
|
||||
}
|
||||
|
||||
refEx.setNameResolved(true);
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new search results, so that referral processing
|
||||
// can continue
|
||||
((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
|
||||
|
||||
return (se);
|
||||
|
||||
} catch (LdapReferralException e) {
|
||||
|
||||
// append (referrals from) the exception that generated this
|
||||
// context to the new exception, so that referral processing
|
||||
// can continue
|
||||
|
||||
e.appendUnprocessedReferrals(refEx);
|
||||
throw (NamingException)(e.fillInStackTrace());
|
||||
|
||||
} catch (NamingException e) {
|
||||
|
||||
// record the exception if there are no remaining referrals
|
||||
if ((refEx != null) && (! refEx.hasMoreReferrals())) {
|
||||
refEx.setNamingException(e);
|
||||
}
|
||||
if ((refEx != null) &&
|
||||
(refEx.hasMoreReferrals() ||
|
||||
refEx.hasMoreReferralExceptions())) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameInNamespace() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
return urlName != null && !urlName.isEmpty() ? urlName.get(0) : "";
|
||||
}
|
||||
|
||||
// ---------------------- LdapContext ---------------------
|
||||
|
||||
public ExtendedResponse extendedOperation(ExtendedRequest request)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).extendedOperation(request);
|
||||
}
|
||||
|
||||
public LdapContext newInstance(Control[] requestControls)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).newInstance(requestControls);
|
||||
}
|
||||
|
||||
public void reconnect(Control[] connCtls) throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
((LdapContext)refCtx).reconnect(connCtls);
|
||||
}
|
||||
|
||||
public Control[] getConnectControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
return ((LdapContext)refCtx).getConnectControls();
|
||||
}
|
||||
|
||||
public void setRequestControls(Control[] requestControls)
|
||||
throws NamingException {
|
||||
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
|
||||
((LdapContext)refCtx).setRequestControls(requestControls);
|
||||
}
|
||||
|
||||
public Control[] getRequestControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
return ((LdapContext)refCtx).getRequestControls();
|
||||
}
|
||||
|
||||
public Control[] getResponseControls() throws NamingException {
|
||||
if (skipThisReferral) {
|
||||
throw (NamingException)
|
||||
((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
|
||||
}
|
||||
|
||||
if (!(refCtx instanceof LdapContext)) {
|
||||
throw new NotContextException(
|
||||
"Referral context not an instance of LdapContext");
|
||||
}
|
||||
return ((LdapContext)refCtx).getResponseControls();
|
||||
}
|
||||
|
||||
// ---------------------- Private methods ---------------------
|
||||
private Name toName(String name) throws InvalidNameException {
|
||||
return name.equals("") ? new CompositeName() :
|
||||
new CompositeName().add(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the DN component from the LDAP URL (if present) to override the
|
||||
* supplied DN.
|
||||
*/
|
||||
private Name overrideName(Name name) throws InvalidNameException {
|
||||
return (urlName == null ? name : urlName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the attributes and scope components from the LDAP URL (if present)
|
||||
* to override the corrpesonding components supplied in SearchControls.
|
||||
*/
|
||||
private SearchControls overrideAttributesAndScope(SearchControls cons) {
|
||||
SearchControls urlCons;
|
||||
|
||||
if ((urlScope != null) || (urlAttrs != null)) {
|
||||
urlCons = new SearchControls(cons.getSearchScope(),
|
||||
cons.getCountLimit(),
|
||||
cons.getTimeLimit(),
|
||||
cons.getReturningAttributes(),
|
||||
cons.getReturningObjFlag(),
|
||||
cons.getDerefLinkFlag());
|
||||
|
||||
if (urlScope != null) {
|
||||
if (urlScope.equals("base")) {
|
||||
urlCons.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||
} else if (urlScope.equals("one")) {
|
||||
urlCons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
|
||||
} else if (urlScope.equals("sub")) {
|
||||
urlCons.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlAttrs != null) {
|
||||
StringTokenizer tokens = new StringTokenizer(urlAttrs, ",");
|
||||
int count = tokens.countTokens();
|
||||
String[] attrs = new String[count];
|
||||
for (int i = 0; i < count; i ++) {
|
||||
attrs[i] = tokens.nextToken();
|
||||
}
|
||||
urlCons.setReturningAttributes(attrs);
|
||||
}
|
||||
|
||||
return urlCons;
|
||||
|
||||
} else {
|
||||
return cons;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the filter component from the LDAP URL (if present) to override the
|
||||
* supplied filter.
|
||||
*/
|
||||
private String overrideFilter(String filter) {
|
||||
return (urlFilter == null ? filter : urlFilter);
|
||||
}
|
||||
|
||||
}
|
||||
434
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralException.java
Normal file
434
jdkSrc/jdk8/com/sun/jndi/ldap/LdapReferralException.java
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2017, 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This exception is raised when a referral to an alternative context
|
||||
* is encountered.
|
||||
* <p>
|
||||
* An <tt>LdapReferralException</tt> object contains one or more referrals.
|
||||
* Each referral is an alternative location for the same target entry.
|
||||
* For example, a referral may be an LDAP URL.
|
||||
* The referrals are attempted in sequence until one is successful or
|
||||
* all have failed. In the case of the latter then the exception generated
|
||||
* by the final referral is recorded and presented later.
|
||||
* <p>
|
||||
* A referral may be skipped or may be retried. For example, in the case
|
||||
* of an authentication error, a referral may be retried with different
|
||||
* environment properties.
|
||||
* <p>
|
||||
* An <tt>LdapReferralException</tt> object may also contain a reference
|
||||
* to a chain of unprocessed <tt>LdapReferralException</tt> objects.
|
||||
* Once the current set of referrals have been exhausted and unprocessed
|
||||
* <tt>LdapReferralException</tt> objects remain, then the
|
||||
* <tt>LdapReferralException</tt> object referenced by the current
|
||||
* object is thrown and the cycle continues.
|
||||
* <p>
|
||||
* If new <tt>LdapReferralException</tt> objects are generated while
|
||||
* following an existing referral then these new objects are appended
|
||||
* to the end of the chain of unprocessed <tt>LdapReferralException</tt>
|
||||
* objects.
|
||||
* <p>
|
||||
* If an exception was recorded while processing a chain of
|
||||
* <tt>LdapReferralException</tt> objects then is is throw once
|
||||
* processing has completed.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class LdapReferralException extends
|
||||
javax.naming.ldap.LdapReferralException {
|
||||
private static final long serialVersionUID = 627059076356906399L;
|
||||
|
||||
// ----------- fields initialized in constructor ---------------
|
||||
private int handleReferrals;
|
||||
private Hashtable<?,?> envprops;
|
||||
private String nextName;
|
||||
private Control[] reqCtls;
|
||||
|
||||
// ----------- fields that have defaults -----------------------
|
||||
private Vector<?> referrals = null; // alternatives,set by setReferralInfo()
|
||||
private int referralIndex = 0; // index into referrals
|
||||
private int referralCount = 0; // count of referrals
|
||||
private boolean foundEntry = false; // will stop when entry is found
|
||||
private boolean skipThisReferral = false;
|
||||
private int hopCount = 1;
|
||||
private NamingException errorEx = null;
|
||||
private String newRdn = null;
|
||||
private boolean debug = false;
|
||||
LdapReferralException nextReferralEx = null; // referral ex. chain
|
||||
|
||||
/**
|
||||
* Constructs a new instance of LdapReferralException.
|
||||
* @param resolvedName The part of the name that has been successfully
|
||||
* resolved.
|
||||
* @param resolvedObj The object to which resolution was successful.
|
||||
* @param remainingName The remaining unresolved portion of the name.
|
||||
* @param explanation Additional detail about this exception.
|
||||
*/
|
||||
LdapReferralException(Name resolvedName,
|
||||
Object resolvedObj,
|
||||
Name remainingName,
|
||||
String explanation,
|
||||
Hashtable<?,?> envprops,
|
||||
String nextName,
|
||||
int handleReferrals,
|
||||
Control[] reqCtls) {
|
||||
|
||||
super(explanation);
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException constructor");
|
||||
|
||||
setResolvedName(resolvedName);
|
||||
setResolvedObj(resolvedObj);
|
||||
setRemainingName(remainingName);
|
||||
this.envprops = envprops;
|
||||
this.nextName = nextName;
|
||||
this.handleReferrals = handleReferrals;
|
||||
|
||||
// If following referral, request controls are passed to referral ctx
|
||||
this.reqCtls =
|
||||
(handleReferrals == LdapClient.LDAP_REF_FOLLOW ||
|
||||
handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? reqCtls : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The current environment properties are re-used.
|
||||
*/
|
||||
public Context getReferralContext() throws NamingException {
|
||||
return getReferralContext(envprops, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The supplied environment properties are used.
|
||||
*/
|
||||
public Context getReferralContext(Hashtable<?,?> newProps) throws
|
||||
NamingException {
|
||||
return getReferralContext(newProps, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a context at which to continue processing.
|
||||
* The supplied environment properties and connection controls are used.
|
||||
*/
|
||||
public Context getReferralContext(Hashtable<?,?> newProps, Control[] connCtls)
|
||||
throws NamingException {
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getReferralContext");
|
||||
|
||||
LdapReferralContext refCtx = new LdapReferralContext(
|
||||
this, newProps, connCtls, reqCtls,
|
||||
nextName, skipThisReferral, handleReferrals);
|
||||
|
||||
refCtx.setHopCount(hopCount + 1);
|
||||
|
||||
if (skipThisReferral) {
|
||||
skipThisReferral = false; // reset
|
||||
}
|
||||
return (Context)refCtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets referral information.
|
||||
*/
|
||||
public Object getReferralInfo() {
|
||||
if (debug) {
|
||||
System.out.println("LdapReferralException.getReferralInfo");
|
||||
System.out.println(" referralIndex=" + referralIndex);
|
||||
}
|
||||
|
||||
if (hasMoreReferrals()) {
|
||||
return referrals.elementAt(referralIndex);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current referral as one to be retried.
|
||||
*/
|
||||
public void retryReferral() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.retryReferral");
|
||||
|
||||
if (referralIndex > 0)
|
||||
referralIndex--; // decrement index
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current referral as one to be ignored.
|
||||
* Returns false when there are no referrals remaining to be processed.
|
||||
*/
|
||||
public boolean skipReferral() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.skipReferral");
|
||||
|
||||
skipThisReferral = true;
|
||||
|
||||
// advance to next referral
|
||||
try {
|
||||
getNextReferral();
|
||||
} catch (ReferralException e) {
|
||||
// mask the referral exception
|
||||
}
|
||||
|
||||
return (hasMoreReferrals() || hasMoreReferralExceptions());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets referral information.
|
||||
*/
|
||||
void setReferralInfo(Vector<?> referrals, boolean continuationRef) {
|
||||
// %%% continuationRef is currently ignored
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setReferralInfo");
|
||||
|
||||
this.referrals = referrals;
|
||||
referralCount = (referrals == null) ? 0 : referrals.size();
|
||||
|
||||
if (debug) {
|
||||
if (referrals != null) {
|
||||
for (int i = 0; i < referralCount; i++) {
|
||||
System.out.println(" [" + i + "] " + referrals.elementAt(i));
|
||||
}
|
||||
} else {
|
||||
System.out.println("setReferralInfo : referrals == null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next referral. When the current set of referrals have
|
||||
* been exhausted then the next referral exception is thrown, if available.
|
||||
*/
|
||||
String getNextReferral() throws ReferralException {
|
||||
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNextReferral");
|
||||
|
||||
if (hasMoreReferrals()) {
|
||||
return (String)referrals.elementAt(referralIndex++);
|
||||
} else if (hasMoreReferralExceptions()) {
|
||||
throw nextReferralEx;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the supplied (chain of) referral exception onto the end of
|
||||
* the current (chain of) referral exception. Spent referral exceptions
|
||||
* are trimmed off.
|
||||
*/
|
||||
LdapReferralException
|
||||
appendUnprocessedReferrals(LdapReferralException back) {
|
||||
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"LdapReferralException.appendUnprocessedReferrals");
|
||||
dump();
|
||||
if (back != null) {
|
||||
back.dump();
|
||||
}
|
||||
}
|
||||
|
||||
LdapReferralException front = this;
|
||||
|
||||
if (! front.hasMoreReferrals()) {
|
||||
front = nextReferralEx; // trim
|
||||
|
||||
if ((errorEx != null) && (front != null)) {
|
||||
front.setNamingException(errorEx); //advance the saved exception
|
||||
}
|
||||
}
|
||||
|
||||
// don't append onto itself
|
||||
if (this == back) {
|
||||
return front;
|
||||
}
|
||||
|
||||
if ((back != null) && (! back.hasMoreReferrals())) {
|
||||
back = back.nextReferralEx; // trim
|
||||
}
|
||||
|
||||
if (back == null) {
|
||||
return front;
|
||||
}
|
||||
|
||||
// Locate the end of the current chain
|
||||
LdapReferralException ptr = front;
|
||||
while (ptr.nextReferralEx != null) {
|
||||
ptr = ptr.nextReferralEx;
|
||||
}
|
||||
ptr.nextReferralEx = back; // append
|
||||
|
||||
return front;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are any referrals remaining to be processed.
|
||||
* If name resolution has already completed then any remaining
|
||||
* referrals (in the current referral exception) will be ignored.
|
||||
*/
|
||||
boolean hasMoreReferrals() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.hasMoreReferrals");
|
||||
|
||||
return (! foundEntry) && (referralIndex < referralCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if there are any referral exceptions remaining to be processed.
|
||||
*/
|
||||
boolean hasMoreReferralExceptions() {
|
||||
if (debug)
|
||||
System.out.println(
|
||||
"LdapReferralException.hasMoreReferralExceptions");
|
||||
|
||||
return (nextReferralEx != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the counter which records the number of hops that result
|
||||
* from following a sequence of referrals.
|
||||
*/
|
||||
void setHopCount(int hopCount) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setHopCount");
|
||||
|
||||
this.hopCount = hopCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to indicate that the target name has been resolved.
|
||||
*/
|
||||
void setNameResolved(boolean resolved) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNameResolved");
|
||||
|
||||
foundEntry = resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exception generated while processing a referral.
|
||||
* Only the first exception is recorded.
|
||||
*/
|
||||
void setNamingException(NamingException e) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNamingException");
|
||||
|
||||
if (errorEx == null) {
|
||||
e.setRootCause(this); //record the referral exception that caused it
|
||||
errorEx = e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new RDN name.
|
||||
*/
|
||||
String getNewRdn() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNewRdn");
|
||||
|
||||
return newRdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the new RDN name so that the rename operation can be completed
|
||||
* (when a referral is being followed).
|
||||
*/
|
||||
void setNewRdn(String newRdn) {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.setNewRdn");
|
||||
|
||||
this.newRdn = newRdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception generated while processing a referral.
|
||||
*/
|
||||
NamingException getNamingException() {
|
||||
if (debug)
|
||||
System.out.println("LdapReferralException.getNamingException");
|
||||
|
||||
return errorEx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the state of each element in a chain of LdapReferralException
|
||||
* objects.
|
||||
*/
|
||||
void dump() {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("LdapReferralException.dump");
|
||||
LdapReferralException ptr = this;
|
||||
while (ptr != null) {
|
||||
ptr.dumpState();
|
||||
ptr = ptr.nextReferralEx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the state of this LdapReferralException object.
|
||||
*/
|
||||
private void dumpState() {
|
||||
System.out.println("LdapReferralException.dumpState");
|
||||
System.out.println(" hashCode=" + hashCode());
|
||||
System.out.println(" foundEntry=" + foundEntry);
|
||||
System.out.println(" skipThisReferral=" + skipThisReferral);
|
||||
System.out.println(" referralIndex=" + referralIndex);
|
||||
|
||||
if (referrals != null) {
|
||||
System.out.println(" referrals:");
|
||||
for (int i = 0; i < referralCount; i++) {
|
||||
System.out.println(" [" + i + "] " + referrals.elementAt(i));
|
||||
}
|
||||
} else {
|
||||
System.out.println(" referrals=null");
|
||||
}
|
||||
|
||||
System.out.println(" errorEx=" + errorEx);
|
||||
|
||||
if (nextReferralEx == null) {
|
||||
System.out.println(" nextRefEx=null");
|
||||
} else {
|
||||
System.out.println(" nextRefEx=" + nextReferralEx.hashCode());
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
141
jdkSrc/jdk8/com/sun/jndi/ldap/LdapRequest.java
Normal file
141
jdkSrc/jdk8/com/sun/jndi/ldap/LdapRequest.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2020, 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
final class LdapRequest {
|
||||
|
||||
private final static BerDecoder EOF = new BerDecoder(new byte[]{}, -1, 0);
|
||||
private final static String CLOSE_MSG = "LDAP connection has been closed";
|
||||
private final static String TIMEOUT_MSG_FMT = "LDAP response read timed out, timeout used: %d ms.";
|
||||
|
||||
LdapRequest next; // Set/read in synchronized Connection methods
|
||||
final int msgId; // read-only
|
||||
|
||||
private final BlockingQueue<BerDecoder> replies;
|
||||
private volatile boolean cancelled;
|
||||
private volatile boolean closed;
|
||||
private volatile boolean completed;
|
||||
private final boolean pauseAfterReceipt;
|
||||
|
||||
LdapRequest(int msgId, boolean pause, int replyQueueCapacity) {
|
||||
this.msgId = msgId;
|
||||
this.pauseAfterReceipt = pause;
|
||||
if (replyQueueCapacity == -1) {
|
||||
this.replies = new LinkedBlockingQueue<>();
|
||||
} else {
|
||||
this.replies = new LinkedBlockingQueue<>(8 * replyQueueCapacity / 10);
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
cancelled = true;
|
||||
replies.offer(EOF);
|
||||
}
|
||||
|
||||
synchronized void close() {
|
||||
closed = true;
|
||||
replies.offer(EOF);
|
||||
}
|
||||
|
||||
private boolean isClosed() {
|
||||
return closed && (replies.size() == 0 || replies.peek() == EOF);
|
||||
}
|
||||
|
||||
synchronized boolean addReplyBer(BerDecoder ber) {
|
||||
// check the closed boolean value here as we don't want anything
|
||||
// to be added to the queue after close() has been called.
|
||||
if (cancelled || closed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// peek at the BER buffer to check if it is a SearchResultDone PDU
|
||||
try {
|
||||
ber.parseSeq(null);
|
||||
ber.parseInt();
|
||||
completed = (ber.peekByte() == LdapClient.LDAP_REP_RESULT);
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
ber.reset();
|
||||
|
||||
// Add a new reply to the queue of unprocessed replies.
|
||||
try {
|
||||
replies.put(ber);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return pauseAfterReceipt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read reply BER
|
||||
* @param millis timeout, infinite if the value is negative
|
||||
* @return BerDecoder if reply was read successfully
|
||||
* @throws CommunicationException request has been canceled and request does not need to be abandoned
|
||||
* @throws NamingException request has been closed or timed out. Request does need to be abandoned
|
||||
* @throws InterruptedException LDAP operation has been interrupted
|
||||
*/
|
||||
BerDecoder getReplyBer(long millis) throws NamingException,
|
||||
InterruptedException {
|
||||
if (cancelled) {
|
||||
throw new CommunicationException("Request: " + msgId +
|
||||
" cancelled");
|
||||
}
|
||||
if (isClosed()) {
|
||||
throw new NamingException(CLOSE_MSG);
|
||||
}
|
||||
|
||||
BerDecoder result = millis > 0 ?
|
||||
replies.poll(millis, TimeUnit.MILLISECONDS) : replies.take();
|
||||
|
||||
if (cancelled) {
|
||||
throw new CommunicationException("Request: " + msgId +
|
||||
" cancelled");
|
||||
}
|
||||
|
||||
// poll from 'replies' blocking queue ended-up with timeout
|
||||
if (result == null) {
|
||||
throw new NamingException(String.format(TIMEOUT_MSG_FMT, millis));
|
||||
}
|
||||
// Unexpected EOF can be caused by connection closure or cancellation
|
||||
if (result == EOF) {
|
||||
throw new NamingException(CLOSE_MSG);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean hasSearchCompleted() {
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
82
jdkSrc/jdk8/com/sun/jndi/ldap/LdapResult.java
Normal file
82
jdkSrc/jdk8/com/sun/jndi/ldap/LdapResult.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* %%% public for use by LdapSasl %%%
|
||||
*/
|
||||
public final class LdapResult {
|
||||
int msgId;
|
||||
public int status; // %%% public for use by LdapSasl
|
||||
String matchedDN;
|
||||
String errorMessage;
|
||||
// Vector<String | Vector<String>>
|
||||
Vector<Vector<String>> referrals = null;
|
||||
LdapReferralException refEx = null;
|
||||
Vector<LdapEntry> entries = null;
|
||||
Vector<Control> resControls = null;
|
||||
public byte[] serverCreds = null; // %%% public for use by LdapSasl
|
||||
String extensionId = null; // string OID
|
||||
byte[] extensionValue = null; // BER OCTET STRING
|
||||
|
||||
|
||||
// This function turns an LdapResult that came from a compare operation
|
||||
// into one that looks like it came from a search operation. This is
|
||||
// useful when the caller asked the context to do a search, but it was
|
||||
// carried out as a compare. In this case, the client still expects a
|
||||
// result that looks like it came from a search.
|
||||
boolean compareToSearchResult(String name) {
|
||||
boolean successful = false;
|
||||
|
||||
switch (status) {
|
||||
case LdapClient.LDAP_COMPARE_TRUE:
|
||||
status = LdapClient.LDAP_SUCCESS;
|
||||
entries = new Vector<>(1,1);
|
||||
Attributes attrs = new BasicAttributes(LdapClient.caseIgnore);
|
||||
LdapEntry entry = new LdapEntry( name, attrs );
|
||||
entries.addElement(entry);
|
||||
successful = true;
|
||||
break;
|
||||
|
||||
case LdapClient.LDAP_COMPARE_FALSE:
|
||||
status = LdapClient.LDAP_SUCCESS;
|
||||
entries = new Vector<>(0);
|
||||
successful = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
successful = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
437
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaCtx.java
Normal file
437
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaCtx.java
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import java.util.Hashtable;
|
||||
import com.sun.jndi.toolkit.dir.HierMemDirCtx;
|
||||
|
||||
/**
|
||||
* This is the class used to implement LDAP's GetSchema call.
|
||||
*
|
||||
* It subclasses HierMemDirContext for most of the functionality. It
|
||||
* overrides functions that cause the schema definitions to change.
|
||||
* In such a case, it write the schema to the LdapServer and (assuming
|
||||
* there are no errors), calls it's superclass's equivalent function.
|
||||
* Thus, the schema tree and the LDAP server's schema attributes are
|
||||
* always in sync.
|
||||
*/
|
||||
|
||||
final class LdapSchemaCtx extends HierMemDirCtx {
|
||||
|
||||
static private final boolean debug = false;
|
||||
|
||||
private static final int LEAF = 0; // schema object (e.g. attribute type defn)
|
||||
private static final int SCHEMA_ROOT = 1; // schema tree root
|
||||
static final int OBJECTCLASS_ROOT = 2; // root of object class subtree
|
||||
static final int ATTRIBUTE_ROOT = 3; // root of attribute type subtree
|
||||
static final int SYNTAX_ROOT = 4; // root of syntax subtree
|
||||
static final int MATCHRULE_ROOT = 5; // root of matching rule subtree
|
||||
static final int OBJECTCLASS = 6; // an object class definition
|
||||
static final int ATTRIBUTE = 7; // an attribute type definition
|
||||
static final int SYNTAX = 8; // a syntax definition
|
||||
static final int MATCHRULE = 9; // a matching rule definition
|
||||
|
||||
private SchemaInfo info= null;
|
||||
private boolean setupMode = true;
|
||||
|
||||
private int objectType;
|
||||
|
||||
static DirContext createSchemaTree(Hashtable<String,Object> env,
|
||||
String subschemasubentry, LdapCtx schemaEntry,
|
||||
Attributes schemaAttrs, boolean netscapeBug)
|
||||
throws NamingException {
|
||||
try {
|
||||
LdapSchemaParser parser = new LdapSchemaParser(netscapeBug);
|
||||
|
||||
SchemaInfo allinfo = new SchemaInfo(subschemasubentry,
|
||||
schemaEntry, parser);
|
||||
|
||||
LdapSchemaCtx root = new LdapSchemaCtx(SCHEMA_ROOT, env, allinfo);
|
||||
LdapSchemaParser.LDAP2JNDISchema(schemaAttrs, root);
|
||||
return root;
|
||||
} catch (NamingException e) {
|
||||
schemaEntry.close(); // cleanup
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by createNewCtx
|
||||
private LdapSchemaCtx(int objectType, Hashtable<String,Object> environment,
|
||||
SchemaInfo info) {
|
||||
super(environment, LdapClient.caseIgnore);
|
||||
|
||||
this.objectType = objectType;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
// override HierMemDirCtx.close to prevent premature GC of shared data
|
||||
public void close() throws NamingException {
|
||||
info.close();
|
||||
}
|
||||
|
||||
// override to ignore obj and use attrs
|
||||
// treat same as createSubcontext
|
||||
final public void bind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
if (!setupMode) {
|
||||
if (obj != null) {
|
||||
throw new IllegalArgumentException("obj must be null");
|
||||
}
|
||||
|
||||
// Update server
|
||||
addServerSchema(attrs);
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
LdapSchemaCtx newEntry =
|
||||
(LdapSchemaCtx)super.doCreateSubcontext(name, attrs);
|
||||
}
|
||||
|
||||
final protected void doBind(Name name, Object obj, Attributes attrs,
|
||||
boolean useFactory) throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException(
|
||||
"Cannot bind arbitrary object; use createSubcontext()");
|
||||
} else {
|
||||
super.doBind(name, obj, attrs, false); // always ignore factories
|
||||
}
|
||||
}
|
||||
|
||||
// override to use bind() instead
|
||||
final public void rebind(Name name, Object obj, Attributes attrs)
|
||||
throws NamingException {
|
||||
try {
|
||||
doLookup(name, false);
|
||||
throw new SchemaViolationException(
|
||||
"Cannot replace existing schema object");
|
||||
} catch (NameNotFoundException e) {
|
||||
bind(name, obj, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doRebind(Name name, Object obj, Attributes attrs,
|
||||
boolean useFactory) throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException(
|
||||
"Cannot bind arbitrary object; use createSubcontext()");
|
||||
} else {
|
||||
super.doRebind(name, obj, attrs, false); // always ignore factories
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doUnbind(Name name) throws NamingException {
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
try {
|
||||
// Lookup entry from memory
|
||||
LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);
|
||||
|
||||
deleteServerSchema(target.attrs);
|
||||
} catch (NameNotFoundException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Update in-memory copy
|
||||
super.doUnbind(name);
|
||||
}
|
||||
|
||||
final protected void doRename(Name oldname, Name newname)
|
||||
throws NamingException {
|
||||
if (!setupMode) {
|
||||
throw new SchemaViolationException("Cannot rename a schema object");
|
||||
} else {
|
||||
super.doRename(oldname, newname);
|
||||
}
|
||||
}
|
||||
|
||||
final protected void doDestroySubcontext(Name name) throws NamingException {
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
try {
|
||||
// Lookup entry from memory
|
||||
LdapSchemaCtx target = (LdapSchemaCtx)doLookup(name, false);
|
||||
|
||||
deleteServerSchema(target.attrs);
|
||||
} catch (NameNotFoundException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
super.doDestroySubcontext(name);
|
||||
}
|
||||
|
||||
// Called to create oc, attr, syntax or matching rule roots and leaf entries
|
||||
final LdapSchemaCtx setup(int objectType, String name, Attributes attrs)
|
||||
throws NamingException{
|
||||
try {
|
||||
setupMode = true;
|
||||
LdapSchemaCtx answer =
|
||||
(LdapSchemaCtx) super.doCreateSubcontext(
|
||||
new CompositeName(name), attrs);
|
||||
|
||||
answer.objectType = objectType;
|
||||
answer.setupMode = false;
|
||||
return answer;
|
||||
} finally {
|
||||
setupMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
final protected DirContext doCreateSubcontext(Name name, Attributes attrs)
|
||||
throws NamingException {
|
||||
|
||||
if (attrs == null || attrs.size() == 0) {
|
||||
throw new SchemaViolationException(
|
||||
"Must supply attributes describing schema");
|
||||
}
|
||||
|
||||
if (!setupMode) {
|
||||
// Update server
|
||||
addServerSchema(attrs);
|
||||
}
|
||||
|
||||
// Update in-memory copy
|
||||
LdapSchemaCtx newEntry =
|
||||
(LdapSchemaCtx) super.doCreateSubcontext(name, attrs);
|
||||
return newEntry;
|
||||
}
|
||||
|
||||
final private static Attributes deepClone(Attributes orig)
|
||||
throws NamingException {
|
||||
BasicAttributes copy = new BasicAttributes(true);
|
||||
NamingEnumeration<? extends Attribute> attrs = orig.getAll();
|
||||
while (attrs.hasMore()) {
|
||||
copy.put((Attribute)attrs.next().clone());
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
final protected void doModifyAttributes(ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (setupMode) {
|
||||
super.doModifyAttributes(mods);
|
||||
} else {
|
||||
Attributes copy = deepClone(attrs);
|
||||
|
||||
// Apply modifications to copy
|
||||
applyMods(mods, copy);
|
||||
|
||||
// Update server copy
|
||||
modifyServerSchema(attrs, copy);
|
||||
|
||||
// Update in-memory copy
|
||||
attrs = copy;
|
||||
}
|
||||
}
|
||||
|
||||
// we override this so the superclass creates the right kind of contexts
|
||||
// Default is to create LEAF objects; caller will change after creation
|
||||
// if necessary
|
||||
final protected HierMemDirCtx createNewCtx() {
|
||||
LdapSchemaCtx ctx = new LdapSchemaCtx(LEAF, myEnv, info);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
final private void addServerSchema(Attributes attrs)
|
||||
throws NamingException {
|
||||
Attribute schemaAttr;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS_ROOT:
|
||||
schemaAttr = info.parser.stringifyObjDesc(attrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE_ROOT:
|
||||
schemaAttr = info.parser.stringifyAttrDesc(attrs);
|
||||
break;
|
||||
|
||||
case SYNTAX_ROOT:
|
||||
schemaAttr = info.parser.stringifySyntaxDesc(attrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE_ROOT:
|
||||
schemaAttr = info.parser.stringifyMatchRuleDesc(attrs);
|
||||
break;
|
||||
|
||||
case SCHEMA_ROOT:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot create new entry under schema root");
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot create child of schema object");
|
||||
}
|
||||
|
||||
Attributes holder = new BasicAttributes(true);
|
||||
holder.put(schemaAttr);
|
||||
//System.err.println((String)schemaAttr.get());
|
||||
|
||||
info.modifyAttributes(myEnv, DirContext.ADD_ATTRIBUTE, holder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When we delete an entry, we use the original to make sure that
|
||||
* any formatting inconsistencies are eliminated.
|
||||
* This is because we're just deleting a value from an attribute
|
||||
* on the server and there might not be any checks for extra spaces
|
||||
* or parens.
|
||||
*/
|
||||
final private void deleteServerSchema(Attributes origAttrs)
|
||||
throws NamingException {
|
||||
|
||||
Attribute origAttrVal;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS_ROOT:
|
||||
origAttrVal = info.parser.stringifyObjDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE_ROOT:
|
||||
origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case SYNTAX_ROOT:
|
||||
origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE_ROOT:
|
||||
origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
|
||||
break;
|
||||
|
||||
case SCHEMA_ROOT:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot delete schema root");
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot delete child of schema object");
|
||||
}
|
||||
|
||||
ModificationItem[] mods = new ModificationItem[1];
|
||||
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);
|
||||
|
||||
info.modifyAttributes(myEnv, mods);
|
||||
}
|
||||
|
||||
/**
|
||||
* When we modify an entry, we use the original attribute value
|
||||
* in the schema to make sure that any formatting inconsistencies
|
||||
* are eliminated. A modification is done by deleting the original
|
||||
* value and adding a new value with the modification.
|
||||
*/
|
||||
final private void modifyServerSchema(Attributes origAttrs,
|
||||
Attributes newAttrs) throws NamingException {
|
||||
|
||||
Attribute newAttrVal;
|
||||
Attribute origAttrVal;
|
||||
|
||||
switch (objectType) {
|
||||
case OBJECTCLASS:
|
||||
origAttrVal = info.parser.stringifyObjDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyObjDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case ATTRIBUTE:
|
||||
origAttrVal = info.parser.stringifyAttrDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyAttrDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case SYNTAX:
|
||||
origAttrVal = info.parser.stringifySyntaxDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifySyntaxDesc(newAttrs);
|
||||
break;
|
||||
|
||||
case MATCHRULE:
|
||||
origAttrVal = info.parser.stringifyMatchRuleDesc(origAttrs);
|
||||
newAttrVal = info.parser.stringifyMatchRuleDesc(newAttrs);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SchemaViolationException(
|
||||
"Cannot modify schema root");
|
||||
}
|
||||
|
||||
ModificationItem[] mods = new ModificationItem[2];
|
||||
mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, origAttrVal);
|
||||
mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, newAttrVal);
|
||||
|
||||
info.modifyAttributes(myEnv, mods);
|
||||
}
|
||||
|
||||
final static private class SchemaInfo {
|
||||
private LdapCtx schemaEntry;
|
||||
private String schemaEntryName;
|
||||
LdapSchemaParser parser;
|
||||
private String host;
|
||||
private int port;
|
||||
private boolean hasLdapsScheme;
|
||||
|
||||
SchemaInfo(String schemaEntryName, LdapCtx schemaEntry,
|
||||
LdapSchemaParser parser) {
|
||||
this.schemaEntryName = schemaEntryName;
|
||||
this.schemaEntry = schemaEntry;
|
||||
this.parser = parser;
|
||||
this.port = schemaEntry.port_number;
|
||||
this.host = schemaEntry.hostname;
|
||||
this.hasLdapsScheme = schemaEntry.hasLdapsScheme;
|
||||
}
|
||||
|
||||
synchronized void close() throws NamingException {
|
||||
if (schemaEntry != null) {
|
||||
schemaEntry.close();
|
||||
schemaEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
private LdapCtx reopenEntry(Hashtable<?,?> env) throws NamingException {
|
||||
// Use subschemasubentry name as DN
|
||||
return new LdapCtx(schemaEntryName, host, port,
|
||||
env, hasLdapsScheme);
|
||||
}
|
||||
|
||||
synchronized void modifyAttributes(Hashtable<?,?> env,
|
||||
ModificationItem[] mods)
|
||||
throws NamingException {
|
||||
if (schemaEntry == null) {
|
||||
schemaEntry = reopenEntry(env);
|
||||
}
|
||||
schemaEntry.modifyAttributes("", mods);
|
||||
}
|
||||
|
||||
synchronized void modifyAttributes(Hashtable<?,?> env, int mod,
|
||||
Attributes attrs) throws NamingException {
|
||||
if (schemaEntry == null) {
|
||||
schemaEntry = reopenEntry(env);
|
||||
}
|
||||
schemaEntry.modifyAttributes("", mod, attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
1303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaParser.java
Normal file
1303
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSchemaParser.java
Normal file
File diff suppressed because it is too large
Load Diff
223
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSearchEnumeration.java
Normal file
223
jdkSrc/jdk8/com/sun/jndi/ldap/LdapSearchEnumeration.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Vector;
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.*;
|
||||
import javax.naming.ldap.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
final class LdapSearchEnumeration
|
||||
extends AbstractLdapNamingEnumeration<SearchResult> {
|
||||
|
||||
private Name startName; // prefix of names of search results
|
||||
private LdapCtx.SearchArgs searchArgs = null;
|
||||
|
||||
private final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
LdapSearchEnumeration(LdapCtx homeCtx, LdapResult search_results,
|
||||
String starter, LdapCtx.SearchArgs args, Continuation cont)
|
||||
throws NamingException {
|
||||
|
||||
super(homeCtx, search_results,
|
||||
args.name, /* listArg */
|
||||
cont);
|
||||
|
||||
// fully qualified name of starting context of search
|
||||
startName = new LdapName(starter);
|
||||
searchArgs = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SearchResult createItem(String dn, Attributes attrs,
|
||||
Vector<Control> respCtls)
|
||||
throws NamingException {
|
||||
|
||||
Object obj = null;
|
||||
|
||||
String relStart; // name relative to starting search context
|
||||
String relHome; // name relative to homeCtx.currentDN
|
||||
boolean relative = true; // whether relative to currentDN
|
||||
|
||||
// need to strip off all but lowest component of dn
|
||||
// so that is relative to current context (currentDN)
|
||||
|
||||
try {
|
||||
Name parsed = new LdapName(dn);
|
||||
// System.err.println("dn string: " + dn);
|
||||
// System.err.println("dn name: " + parsed);
|
||||
|
||||
if (startName != null && parsed.startsWith(startName)) {
|
||||
relStart = parsed.getSuffix(startName.size()).toString();
|
||||
relHome = parsed.getSuffix(homeCtx.currentParsedDN.size()).toString();
|
||||
} else {
|
||||
relative = false;
|
||||
relHome = relStart =
|
||||
LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
|
||||
dn, homeCtx.hasLdapsScheme);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
// could not parse name
|
||||
relative = false;
|
||||
relHome = relStart =
|
||||
LdapURL.toUrlString(homeCtx.hostname, homeCtx.port_number,
|
||||
dn, homeCtx.hasLdapsScheme);
|
||||
}
|
||||
|
||||
// Name relative to search context
|
||||
CompositeName cn = new CompositeName();
|
||||
if (!relStart.equals("")) {
|
||||
cn.add(relStart);
|
||||
}
|
||||
|
||||
// Name relative to homeCtx
|
||||
CompositeName rcn = new CompositeName();
|
||||
if (!relHome.equals("")) {
|
||||
rcn.add(relHome);
|
||||
}
|
||||
//System.err.println("relStart: " + cn);
|
||||
//System.err.println("relHome: " + rcn);
|
||||
|
||||
// Fix attributes to be able to get schema
|
||||
homeCtx.setParents(attrs, rcn);
|
||||
|
||||
// only generate object when requested
|
||||
if (searchArgs.cons.getReturningObjFlag()) {
|
||||
|
||||
if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) {
|
||||
// Entry contains Java-object attributes (ser/ref object)
|
||||
// serialized object or object reference
|
||||
try {
|
||||
obj = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||
@Override
|
||||
public Object run() throws NamingException {
|
||||
return Obj.decodeObject(attrs);
|
||||
}
|
||||
}, acc);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw (NamingException)e.getException();
|
||||
}
|
||||
}
|
||||
if (obj == null) {
|
||||
obj = new LdapCtx(homeCtx, dn);
|
||||
}
|
||||
|
||||
// Call getObjectInstance before removing unrequested attributes
|
||||
try {
|
||||
// rcn is either relative to homeCtx or a fully qualified DN
|
||||
obj = DirectoryManager.getObjectInstance(
|
||||
obj, rcn, (relative ? homeCtx : null),
|
||||
homeCtx.envprops, attrs);
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
NamingException ne =
|
||||
new NamingException(
|
||||
"problem generating object using object factory");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// remove Java attributes from result, if necessary
|
||||
// Even if CLASSNAME attr not there, there might be some
|
||||
// residual attributes
|
||||
|
||||
String[] reqAttrs;
|
||||
if ((reqAttrs = searchArgs.reqAttrs) != null) {
|
||||
// create an attribute set for those requested
|
||||
Attributes rattrs = new BasicAttributes(true); // caseignore
|
||||
for (int i = 0; i < reqAttrs.length; i++) {
|
||||
rattrs.put(reqAttrs[i], null);
|
||||
}
|
||||
for (int i = 0; i < Obj.JAVA_ATTRIBUTES.length; i++) {
|
||||
// Remove Java-object attributes if not requested
|
||||
if (rattrs.get(Obj.JAVA_ATTRIBUTES[i]) == null) {
|
||||
attrs.remove(Obj.JAVA_ATTRIBUTES[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* name in search result is either the stringified composite name
|
||||
* relative to the search context that can be passed directly to
|
||||
* methods of the search context, or the fully qualified DN
|
||||
* which can be used with the initial context.
|
||||
*/
|
||||
SearchResult sr;
|
||||
if (respCtls != null) {
|
||||
sr = new SearchResultWithControls(
|
||||
(relative ? cn.toString() : relStart), obj, attrs,
|
||||
relative, homeCtx.convertControls(respCtls));
|
||||
} else {
|
||||
sr = new SearchResult(
|
||||
(relative ? cn.toString() : relStart),
|
||||
obj, attrs, relative);
|
||||
}
|
||||
sr.setNameInNamespace(dn);
|
||||
return sr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendUnprocessedReferrals(LdapReferralException ex) {
|
||||
|
||||
// a referral has been followed so do not create relative names
|
||||
startName = null;
|
||||
super.appendUnprocessedReferrals(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(
|
||||
LdapReferralContext refCtx) throws NamingException {
|
||||
// repeat the original operation at the new context
|
||||
return (AbstractLdapNamingEnumeration<? extends NameClassPair>)refCtx.search(
|
||||
searchArgs.name, searchArgs.filter, searchArgs.cons);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
|
||||
super.update(ne);
|
||||
|
||||
// Update search-specific variables
|
||||
LdapSearchEnumeration se = (LdapSearchEnumeration)ne;
|
||||
startName = se.startName;
|
||||
//VR - keep original args, don't overwite with current args
|
||||
// searchArgs = se.searchArgs;
|
||||
}
|
||||
|
||||
void setStartName(Name nm) {
|
||||
startName = nm;
|
||||
}
|
||||
}
|
||||
336
jdkSrc/jdk8/com/sun/jndi/ldap/LdapURL.java
Normal file
336
jdkSrc/jdk8/com/sun/jndi/ldap/LdapURL.java
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import com.sun.jndi.toolkit.url.Uri;
|
||||
import com.sun.jndi.toolkit.url.UrlUtil;
|
||||
|
||||
/*
|
||||
* Extract components of an LDAP URL.
|
||||
*
|
||||
* The format of an LDAP URL is defined in RFC 2255 as follows:
|
||||
*
|
||||
* ldapurl = scheme "://" [hostport] ["/"
|
||||
* [dn ["?" [attributes] ["?" [scope]
|
||||
* ["?" [filter] ["?" extensions]]]]]]
|
||||
* scheme = "ldap"
|
||||
* attributes = attrdesc *("," attrdesc)
|
||||
* scope = "base" / "one" / "sub"
|
||||
* dn = distinguishedName from Section 3 of [1]
|
||||
* hostport = hostport from Section 5 of RFC 1738 [5]
|
||||
* attrdesc = AttributeDescription from Section 4.1.5 of [2]
|
||||
* filter = filter from Section 4 of [4]
|
||||
* extensions = extension *("," extension)
|
||||
* extension = ["!"] extype ["=" exvalue]
|
||||
* extype = token / xtoken
|
||||
* exvalue = LDAPString from section 4.1.2 of [2]
|
||||
* token = oid from section 4.1 of [3]
|
||||
* xtoken = ("X-" / "x-") token
|
||||
*
|
||||
* For example,
|
||||
*
|
||||
* ldap://ldap.itd.umich.edu/o=University%20of%20Michigan,c=US
|
||||
* ldap://host.com:6666/o=IMC,c=US??sub?(cn=Babs%20Jensen)
|
||||
*
|
||||
* This class also supports ldaps URLs.
|
||||
*/
|
||||
|
||||
final public class LdapURL extends Uri {
|
||||
|
||||
private static final String PARSE_MODE_PROP = "com.sun.jndi.ldapURLParsing";
|
||||
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
|
||||
|
||||
public static final ParseMode PARSE_MODE;
|
||||
static {
|
||||
PrivilegedAction<String> action =
|
||||
new GetPropertyAction(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
|
||||
ParseMode parseMode = DEFAULT_PARSE_MODE;
|
||||
try {
|
||||
String mode = AccessController.doPrivileged(action);
|
||||
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
|
||||
} catch (Throwable t) {
|
||||
parseMode = DEFAULT_PARSE_MODE;
|
||||
} finally {
|
||||
PARSE_MODE = parseMode;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useSsl = false;
|
||||
private String DN = null;
|
||||
private String attributes = null;
|
||||
private String scope = null;
|
||||
private String filter = null;
|
||||
private String extensions = null;
|
||||
|
||||
/**
|
||||
* Creates an LdapURL object from an LDAP URL string.
|
||||
*/
|
||||
public LdapURL(String url) throws NamingException {
|
||||
|
||||
super();
|
||||
|
||||
try {
|
||||
init(url); // scheme, host, port, path, query
|
||||
useSsl = scheme.equalsIgnoreCase("ldaps");
|
||||
|
||||
if (! (scheme.equalsIgnoreCase("ldap") || useSsl)) {
|
||||
throw newInvalidURISchemeException(url);
|
||||
}
|
||||
|
||||
parsePathAndQuery(); // DN, attributes, scope, filter, extensions
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
NamingException ne = new NamingException("Cannot parse url: " + url);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
NamingException ne = new NamingException("Cannot parse url: " + url);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MalformedURLException newInvalidURISchemeException(String uri) {
|
||||
return new MalformedURLException("Not an LDAP URL: " + uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSchemeOnly(String uri) {
|
||||
return isLdapSchemeOnly(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParseMode parseMode() {
|
||||
return PARSE_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the URL is an LDAPS URL.
|
||||
*/
|
||||
public boolean useSsl() {
|
||||
return useSsl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's distinguished name.
|
||||
*/
|
||||
public String getDN() {
|
||||
return DN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's attributes.
|
||||
*/
|
||||
public String getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's scope.
|
||||
*/
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's filter.
|
||||
*/
|
||||
public String getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP URL's extensions.
|
||||
*/
|
||||
public String getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a space-separated list of LDAP URLs, returns an array of strings.
|
||||
*/
|
||||
public static String[] fromList(String urlList) throws NamingException {
|
||||
|
||||
String[] urls = new String[(urlList.length() + 1) / 2];
|
||||
int i = 0; // next available index in urls
|
||||
StringTokenizer st = new StringTokenizer(urlList, " ");
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
// we don't accept scheme-only URLs here
|
||||
urls[i++] = validateURI(st.nextToken());
|
||||
}
|
||||
String[] trimmed = new String[i];
|
||||
System.arraycopy(urls, 0, trimmed, 0, i);
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
public static boolean isLdapSchemeOnly(String uri) {
|
||||
return "ldap:".equals(uri) || "ldaps:".equals(uri);
|
||||
}
|
||||
|
||||
public static String validateURI(String uri) {
|
||||
// no validation in legacy mode parsing
|
||||
if (PARSE_MODE == ParseMode.LEGACY) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// special case of scheme-only URIs
|
||||
if (isLdapSchemeOnly(uri)) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
// use java.net.URI to validate the uri syntax
|
||||
return URI.create(uri).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derermines whether an LDAP URL has query components.
|
||||
*/
|
||||
public static boolean hasQueryComponents(String url) {
|
||||
return (url.lastIndexOf('?') != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assembles an LDAP or LDAPS URL string from its components.
|
||||
* If "host" is an IPv6 literal, it may optionally include delimiting
|
||||
* brackets.
|
||||
*/
|
||||
static String toUrlString(String host, int port, String dn, boolean useSsl)
|
||||
{
|
||||
|
||||
try {
|
||||
String h = (host != null) ? host : "";
|
||||
if ((h.indexOf(':') != -1) && (h.charAt(0) != '[')) {
|
||||
h = "[" + h + "]"; // IPv6 literal
|
||||
}
|
||||
String p = (port != -1) ? (":" + port) : "";
|
||||
String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8")) : "";
|
||||
|
||||
String uri = useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
|
||||
return validateURI(uri);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// UTF8 should always be supported
|
||||
throw new IllegalStateException("UTF-8 encoding unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the path and query components of an URL and sets this
|
||||
* object's fields accordingly.
|
||||
*/
|
||||
private void parsePathAndQuery() throws MalformedURLException,
|
||||
UnsupportedEncodingException {
|
||||
|
||||
// path begins with a '/' or is empty
|
||||
|
||||
if (path.equals("")) {
|
||||
return;
|
||||
}
|
||||
|
||||
DN = path.startsWith("/") ? path.substring(1) : path;
|
||||
if (DN.length() > 0) {
|
||||
DN = UrlUtil.decode(DN, "UTF8");
|
||||
}
|
||||
|
||||
// query begins with a '?' or is null
|
||||
|
||||
if (query == null || query.length() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
int currentIndex = 1;
|
||||
int nextQmark;
|
||||
int endIndex;
|
||||
|
||||
// attributes:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
attributes = query.substring(currentIndex, endIndex);
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scope:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
scope = query.substring(currentIndex, endIndex);
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// filter:
|
||||
nextQmark = query.indexOf('?', currentIndex);
|
||||
endIndex = nextQmark == -1 ? query.length() : nextQmark;
|
||||
if (endIndex - currentIndex > 0) {
|
||||
filter = query.substring(currentIndex, endIndex);
|
||||
filter = UrlUtil.decode(filter, "UTF8");
|
||||
}
|
||||
currentIndex = endIndex + 1;
|
||||
if (currentIndex >= query.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// extensions:
|
||||
if (query.length() - currentIndex > 0) {
|
||||
extensions = query.substring(currentIndex);
|
||||
extensions = UrlUtil.decode(extensions, "UTF8");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
LdapURL url = new LdapURL(args[0]);
|
||||
|
||||
System.out.println("Example LDAP URL: " + url.toString());
|
||||
System.out.println(" scheme: " + url.getScheme());
|
||||
System.out.println(" host: " + url.getHost());
|
||||
System.out.println(" port: " + url.getPort());
|
||||
System.out.println(" DN: " + url.getDN());
|
||||
System.out.println(" attrs: " + url.getAttributes());
|
||||
System.out.println(" scope: " + url.getScope());
|
||||
System.out.println(" filter: " + url.getFilter());
|
||||
System.out.println(" extens: " + url.getExtensions());
|
||||
System.out.println("");
|
||||
}
|
||||
*/
|
||||
}
|
||||
66
jdkSrc/jdk8/com/sun/jndi/ldap/ManageReferralControl.java
Normal file
66
jdkSrc/jdk8/com/sun/jndi/ldap/ManageReferralControl.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Request Control for manageDsaIT as
|
||||
* defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-namedref-00.txt">draft-ietf-ldapext-namedref-00.txt</a>.
|
||||
*
|
||||
* The control has no control value.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class ManageReferralControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The manage referral control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.2.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.2";
|
||||
|
||||
private static final long serialVersionUID = 909382692585717224L;
|
||||
|
||||
/**
|
||||
* Constructs a manage referral critical control.
|
||||
*/
|
||||
public ManageReferralControl() {
|
||||
super(OID, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a manage referral control.
|
||||
*
|
||||
* @param criticality The control's criticality setting.
|
||||
*/
|
||||
public ManageReferralControl(boolean criticality) {
|
||||
super(OID, criticality, null);
|
||||
}
|
||||
}
|
||||
45
jdkSrc/jdk8/com/sun/jndi/ldap/NameClassPairWithControls.java
Normal file
45
jdkSrc/jdk8/com/sun/jndi/ldap/NameClassPairWithControls.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class NameClassPairWithControls extends NameClassPair implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public NameClassPairWithControls(String name, String className,
|
||||
Control[] controls) {
|
||||
super(name, className);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 2010738921219112944L;
|
||||
}
|
||||
287
jdkSrc/jdk8/com/sun/jndi/ldap/NamingEventNotifier.java
Normal file
287
jdkSrc/jdk8/com/sun/jndi/ldap/NamingEventNotifier.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.event.*;
|
||||
import javax.naming.ldap.*;
|
||||
import javax.naming.ldap.LdapName;
|
||||
|
||||
import java.util.Vector;
|
||||
import com.sun.jndi.toolkit.ctx.Continuation;
|
||||
|
||||
/**
|
||||
* Gathers information to generate events by using the Persistent Search
|
||||
* control.
|
||||
*<p>
|
||||
* This class maintains a list of listeners all interested in the same
|
||||
* "search" request. It creates a thread that does the persistent search
|
||||
* and blocks, collecting the results of the search.
|
||||
* For each result that it receives from the search, it fires the
|
||||
* corresponding event to its listeners. If an exception is encountered,
|
||||
* it fires a NamingExceptionEvent.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class NamingEventNotifier implements Runnable {
|
||||
private final static boolean debug = false;
|
||||
|
||||
private Vector<NamingListener> namingListeners;
|
||||
private Thread worker;
|
||||
private LdapCtx context;
|
||||
private EventContext eventSrc;
|
||||
private EventSupport support;
|
||||
private NamingEnumeration<SearchResult> results;
|
||||
|
||||
// package private; used by EventSupport to remove it
|
||||
NotifierArgs info;
|
||||
|
||||
NamingEventNotifier(EventSupport support, LdapCtx ctx, NotifierArgs info,
|
||||
NamingListener firstListener) throws NamingException {
|
||||
this.info = info;
|
||||
this.support = support;
|
||||
|
||||
Control psearch;
|
||||
try {
|
||||
psearch = new PersistentSearchControl(
|
||||
info.mask,
|
||||
true /* no info about original entry(s) */,
|
||||
true /* additional info about changes */,
|
||||
Control.CRITICAL);
|
||||
} catch (java.io.IOException e) {
|
||||
NamingException ne = new NamingException(
|
||||
"Problem creating persistent search control");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// Add psearch control to existing list
|
||||
context = (LdapCtx)ctx.newInstance(new Control[]{psearch});
|
||||
eventSrc = ctx;
|
||||
|
||||
namingListeners = new Vector<>();
|
||||
namingListeners.addElement(firstListener);
|
||||
|
||||
worker = Obj.helper.createThread(this);
|
||||
worker.setDaemon(true); // not a user thread
|
||||
worker.start();
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
void addNamingListener(NamingListener l) {
|
||||
namingListeners.addElement(l);
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
void removeNamingListener(NamingListener l) {
|
||||
namingListeners.removeElement(l);
|
||||
}
|
||||
|
||||
// package private; used by EventSupport; namingListener already synchronized
|
||||
boolean hasNamingListeners() {
|
||||
return namingListeners.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute "persistent search".
|
||||
* For each result, create the appropriate NamingEvent and
|
||||
* queue to be dispatched to listeners.
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
Continuation cont = new Continuation();
|
||||
cont.setError(this, info.name);
|
||||
Name nm = (info.name == null || info.name.equals("")) ?
|
||||
new CompositeName() : new CompositeName().add(info.name);
|
||||
|
||||
results = context.searchAux(nm, info.filter, info.controls,
|
||||
true, false, cont);
|
||||
|
||||
// Change root of search results so that it will generate
|
||||
// names relative to the event context instead of that
|
||||
// named by nm
|
||||
((LdapSearchEnumeration)(NamingEnumeration)results)
|
||||
.setStartName(context.currentParsedDN);
|
||||
|
||||
SearchResult si;
|
||||
Control[] respctls;
|
||||
EntryChangeResponseControl ec;
|
||||
long changeNum;
|
||||
|
||||
while (results.hasMore()) {
|
||||
si = results.next();
|
||||
respctls = (si instanceof HasControls) ?
|
||||
((HasControls) si).getControls() : null;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("notifier: " + si);
|
||||
System.err.println("respCtls: " + respctls);
|
||||
}
|
||||
|
||||
// Just process ECs; ignore all the rest
|
||||
if (respctls != null) {
|
||||
for (int i = 0; i < respctls.length; i++) {
|
||||
// %%% Should be checking OID instead of class
|
||||
// %%% in case using someone else's EC ctl
|
||||
if (respctls[i] instanceof EntryChangeResponseControl) {
|
||||
ec = (EntryChangeResponseControl)respctls[i];
|
||||
changeNum = ec.getChangeNumber();
|
||||
switch (ec.getChangeType()) {
|
||||
case EntryChangeResponseControl.ADD:
|
||||
fireObjectAdded(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.DELETE:
|
||||
fireObjectRemoved(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.MODIFY:
|
||||
fireObjectChanged(si, changeNum);
|
||||
break;
|
||||
case EntryChangeResponseControl.RENAME:
|
||||
fireObjectRenamed(si, ec.getPreviousDN(),
|
||||
changeNum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedNamingException e) {
|
||||
if (debug) System.err.println("NamingEventNotifier Interrupted");
|
||||
} catch (NamingException e) {
|
||||
// Fire event to notify NamingExceptionEvent listeners
|
||||
fireNamingException(e);
|
||||
|
||||
// This notifier is no longer valid
|
||||
support.removeDeadNotifier(info);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
if (debug) System.err.println("NamingEventNotifier finished");
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
if (debug) System.err.println("NamingEventNotifier cleanup");
|
||||
|
||||
try {
|
||||
if (results != null) {
|
||||
if (debug) System.err.println("NamingEventNotifier enum closing");
|
||||
results.close(); // this will abandon the search
|
||||
results = null;
|
||||
}
|
||||
if (context != null) {
|
||||
if (debug) System.err.println("NamingEventNotifier ctx closing");
|
||||
context.close();
|
||||
context = null;
|
||||
}
|
||||
} catch (NamingException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the dispatcher so we can be destroyed.
|
||||
* package private; used by EventSupport
|
||||
*/
|
||||
void stop() {
|
||||
if (debug) System.err.println("NamingEventNotifier being stopping");
|
||||
if (worker != null) {
|
||||
worker.interrupt(); // kill our thread
|
||||
worker = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an "object added" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectAdded(Binding newBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_ADDED,
|
||||
newBd, null, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an "object removed" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectRemoved(Binding oldBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingEvent e = new NamingEvent(eventSrc, NamingEvent.OBJECT_REMOVED,
|
||||
null, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an "object changed" event to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectChanged(Binding newBd, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
// Name hasn't changed; construct old binding using name from new binding
|
||||
Binding oldBd = new Binding(newBd.getName(), null, newBd.isRelative());
|
||||
|
||||
NamingEvent e = new NamingEvent(
|
||||
eventSrc, NamingEvent.OBJECT_CHANGED, newBd, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires an "object renamed" to registered NamingListeners.
|
||||
*/
|
||||
private void fireObjectRenamed(Binding newBd, String oldDN, long changeID) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
Binding oldBd = null;
|
||||
try {
|
||||
LdapName dn = new LdapName(oldDN);
|
||||
if (dn.startsWith(context.currentParsedDN)) {
|
||||
String relDN = dn.getSuffix(context.currentParsedDN.size()).toString();
|
||||
oldBd = new Binding(relDN, null);
|
||||
}
|
||||
} catch (NamingException e) {}
|
||||
|
||||
if (oldBd == null) {
|
||||
oldBd = new Binding(oldDN, null, false /* not relative name */);
|
||||
}
|
||||
|
||||
NamingEvent e = new NamingEvent(
|
||||
eventSrc, NamingEvent.OBJECT_RENAMED, newBd, oldBd, new Long(changeID));
|
||||
support.queueEvent(e, namingListeners);
|
||||
}
|
||||
|
||||
private void fireNamingException(NamingException e) {
|
||||
if (namingListeners == null || namingListeners.size() == 0)
|
||||
return;
|
||||
|
||||
NamingExceptionEvent evt = new NamingExceptionEvent(eventSrc, e);
|
||||
support.queueEvent(evt, namingListeners);
|
||||
}
|
||||
}
|
||||
149
jdkSrc/jdk8/com/sun/jndi/ldap/NotifierArgs.java
Normal file
149
jdkSrc/jdk8/com/sun/jndi/ldap/NotifierArgs.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.event.*;
|
||||
|
||||
/**
|
||||
* This class holds the information in an event registration/deregistration
|
||||
* request. This includes the name, filter, search controls and
|
||||
* the different interfaces that the listener implements. This last piece
|
||||
* of information determines which event(s) the listener is interested in.
|
||||
*<p>
|
||||
* It overrides equals() and hashCode() to use all these pieces of
|
||||
* information so that it can be used correctly in a hashtable.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class NotifierArgs {
|
||||
static final int ADDED_MASK = 0x1;
|
||||
static final int REMOVED_MASK = 0x2;
|
||||
static final int CHANGED_MASK = 0x4;
|
||||
static final int RENAMED_MASK = 0x8;
|
||||
|
||||
// these fields are package private; used by NamingEventNotifier
|
||||
String name;
|
||||
String filter;
|
||||
SearchControls controls;
|
||||
int mask;
|
||||
|
||||
// package private
|
||||
NotifierArgs(String name, int scope, NamingListener l) {
|
||||
this(name, "(objectclass=*)", null, l);
|
||||
|
||||
// if scope is not default, create search ctl and set it
|
||||
if (scope != EventContext.ONELEVEL_SCOPE) {
|
||||
controls = new SearchControls();
|
||||
controls.setSearchScope(scope);
|
||||
}
|
||||
}
|
||||
|
||||
// package private
|
||||
NotifierArgs(String name, String filter, SearchControls ctls,
|
||||
NamingListener l) {
|
||||
this.name = name;
|
||||
this.filter = filter;
|
||||
this.controls = ctls;
|
||||
|
||||
if (l instanceof NamespaceChangeListener) {
|
||||
mask |= ADDED_MASK|REMOVED_MASK|RENAMED_MASK;
|
||||
}
|
||||
if (l instanceof ObjectChangeListener) {
|
||||
mask |= CHANGED_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
// checks name, filter, controls
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof NotifierArgs) {
|
||||
NotifierArgs target = (NotifierArgs)obj;
|
||||
return mask == target.mask &&
|
||||
name.equals(target.name) && filter.equals(target.filter) &&
|
||||
checkControls(target.controls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkControls(SearchControls ctls) {
|
||||
if ((controls == null || ctls == null)) {
|
||||
return ctls == controls;
|
||||
}
|
||||
// ctls are nonempty
|
||||
|
||||
return (controls.getSearchScope() == ctls.getSearchScope()) &&
|
||||
(controls.getTimeLimit() == ctls.getTimeLimit()) &&
|
||||
(controls.getDerefLinkFlag() == ctls.getDerefLinkFlag()) &&
|
||||
(controls.getReturningObjFlag() == ctls.getReturningObjFlag()) &&
|
||||
(controls.getCountLimit() == ctls.getCountLimit()) &&
|
||||
checkStringArrays(controls.getReturningAttributes(),
|
||||
ctls.getReturningAttributes());
|
||||
}
|
||||
|
||||
private static boolean checkStringArrays(String[] s1, String[] s2) {
|
||||
if ((s1 == null) || (s2 == null)) {
|
||||
return s1 == s2;
|
||||
}
|
||||
|
||||
// both are nonnull
|
||||
if (s1.length != s2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < s1.length; i++) {
|
||||
if (!s1[i].equals(s2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// save from having to recalculate each time
|
||||
private int sum = -1;
|
||||
public int hashCode() {
|
||||
if (sum == -1)
|
||||
sum = mask + name.hashCode() + filter.hashCode() + controlsCode();
|
||||
return sum;
|
||||
}
|
||||
|
||||
// used in calculating hash code
|
||||
private int controlsCode() {
|
||||
if (controls == null) return 0;
|
||||
|
||||
int total = controls.getTimeLimit() + (int)controls.getCountLimit() +
|
||||
(controls.getDerefLinkFlag() ? 1 : 0) +
|
||||
(controls.getReturningObjFlag() ? 1 : 0);
|
||||
|
||||
String[] attrs = controls.getReturningAttributes();
|
||||
if (attrs != null) {
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
total += attrs[i].hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
669
jdkSrc/jdk8/com/sun/jndi/ldap/Obj.java
Normal file
669
jdkSrc/jdk8/com/sun/jndi/ldap/Obj.java
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.DirectoryManager;
|
||||
import javax.naming.spi.DirStateFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import sun.misc.BASE64Encoder;
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Class containing static methods and constants for dealing with
|
||||
* encoding/decoding JNDI References and Serialized Objects
|
||||
* in LDAP.
|
||||
* @author Vincent Ryan
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class Obj {
|
||||
|
||||
private Obj () {}; // Make sure no one can create one
|
||||
|
||||
// package private; used by Connection
|
||||
static VersionHelper helper = VersionHelper.getVersionHelper();
|
||||
|
||||
// LDAP attributes used to support Java objects.
|
||||
static final String[] JAVA_ATTRIBUTES = {
|
||||
"objectClass",
|
||||
"javaSerializedData",
|
||||
"javaClassName",
|
||||
"javaFactory",
|
||||
"javaCodeBase",
|
||||
"javaReferenceAddress",
|
||||
"javaClassNames",
|
||||
"javaRemoteLocation" // Deprecated
|
||||
};
|
||||
|
||||
static final int OBJECT_CLASS = 0;
|
||||
static final int SERIALIZED_DATA = 1;
|
||||
static final int CLASSNAME = 2;
|
||||
static final int FACTORY = 3;
|
||||
static final int CODEBASE = 4;
|
||||
static final int REF_ADDR = 5;
|
||||
static final int TYPENAME = 6;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
private static final int REMOTE_LOC = 7;
|
||||
|
||||
// LDAP object classes to support Java objects
|
||||
static final String[] JAVA_OBJECT_CLASSES = {
|
||||
"javaContainer",
|
||||
"javaObject",
|
||||
"javaNamingReference",
|
||||
"javaSerializedObject",
|
||||
"javaMarshalledObject",
|
||||
};
|
||||
|
||||
static final String[] JAVA_OBJECT_CLASSES_LOWER = {
|
||||
"javacontainer",
|
||||
"javaobject",
|
||||
"javanamingreference",
|
||||
"javaserializedobject",
|
||||
"javamarshalledobject",
|
||||
};
|
||||
|
||||
static final int STRUCTURAL = 0; // structural object class
|
||||
static final int BASE_OBJECT = 1; // auxiliary java object class
|
||||
static final int REF_OBJECT = 2; // auxiliary reference object class
|
||||
static final int SER_OBJECT = 3; // auxiliary serialized object class
|
||||
static final int MAR_OBJECT = 4; // auxiliary marshalled object class
|
||||
|
||||
/**
|
||||
* Encode an object in LDAP attributes.
|
||||
* Supports binding Referenceable or Reference, Serializable,
|
||||
* and DirContext.
|
||||
*
|
||||
* If the object supports the Referenceable interface then encode
|
||||
* the reference to the object. See encodeReference() for details.
|
||||
*<p>
|
||||
* If the object is serializable, it is stored as follows:
|
||||
* javaClassName
|
||||
* value: Object.getClass();
|
||||
* javaSerializedData
|
||||
* value: serialized form of Object (in binary form).
|
||||
* javaTypeName
|
||||
* value: getTypeNames(Object.getClass());
|
||||
*/
|
||||
private static Attributes encodeObject(char separator,
|
||||
Object obj, Attributes attrs,
|
||||
Attribute objectClass, boolean cloned)
|
||||
throws NamingException {
|
||||
boolean structural =
|
||||
(objectClass.size() == 0 ||
|
||||
(objectClass.size() == 1 && objectClass.contains("top")));
|
||||
|
||||
if (structural) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[STRUCTURAL]);
|
||||
}
|
||||
|
||||
// References
|
||||
if (obj instanceof Referenceable) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
return (encodeReference(separator,
|
||||
((Referenceable)obj).getReference(),
|
||||
attrs, obj));
|
||||
|
||||
} else if (obj instanceof Reference) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[REF_OBJECT]);
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
return (encodeReference(separator, (Reference)obj, attrs, null));
|
||||
|
||||
// Serializable Object
|
||||
} else if (obj instanceof java.io.Serializable) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[BASE_OBJECT]);
|
||||
if (!(objectClass.contains(JAVA_OBJECT_CLASSES[MAR_OBJECT]) ||
|
||||
objectClass.contains(JAVA_OBJECT_CLASSES_LOWER[MAR_OBJECT]))) {
|
||||
objectClass.add(JAVA_OBJECT_CLASSES[SER_OBJECT]);
|
||||
}
|
||||
if (!cloned) {
|
||||
attrs = (Attributes)attrs.clone();
|
||||
}
|
||||
attrs.put(objectClass);
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[SERIALIZED_DATA],
|
||||
serializeObject(obj)));
|
||||
if (attrs.get(JAVA_ATTRIBUTES[CLASSNAME]) == null) {
|
||||
attrs.put(JAVA_ATTRIBUTES[CLASSNAME],
|
||||
obj.getClass().getName());
|
||||
}
|
||||
if (attrs.get(JAVA_ATTRIBUTES[TYPENAME]) == null) {
|
||||
Attribute tAttr =
|
||||
LdapCtxFactory.createTypeNameAttr(obj.getClass());
|
||||
if (tAttr != null) {
|
||||
attrs.put(tAttr);
|
||||
}
|
||||
}
|
||||
// DirContext Object
|
||||
} else if (obj instanceof DirContext) {
|
||||
// do nothing
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"can only bind Referenceable, Serializable, DirContext");
|
||||
}
|
||||
// System.err.println(attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each value in javaCodebase contains a list of space-separated
|
||||
* URLs. Each value is independent; we can pick any of the values
|
||||
* so we just use the first one.
|
||||
* @return an array of URL strings for the codebase
|
||||
*/
|
||||
private static String[] getCodebases(Attribute codebaseAttr) throws
|
||||
NamingException {
|
||||
if (codebaseAttr == null) {
|
||||
return null;
|
||||
} else {
|
||||
StringTokenizer parser =
|
||||
new StringTokenizer((String)codebaseAttr.get());
|
||||
Vector<String> vec = new Vector<>(10);
|
||||
while (parser.hasMoreTokens()) {
|
||||
vec.addElement(parser.nextToken());
|
||||
}
|
||||
String[] answer = new String[vec.size()];
|
||||
for (int i = 0; i < answer.length; i++) {
|
||||
answer[i] = vec.elementAt(i);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode an object from LDAP attribute(s).
|
||||
* The object may be a Reference, or a Serialized object.
|
||||
*
|
||||
* See encodeObject() and encodeReference() for details on formats
|
||||
* expected.
|
||||
*/
|
||||
static Object decodeObject(Attributes attrs)
|
||||
throws NamingException {
|
||||
|
||||
Attribute attr;
|
||||
|
||||
// Get codebase, which is used in all 3 cases.
|
||||
String[] codebases = getCodebases(attrs.get(JAVA_ATTRIBUTES[CODEBASE]));
|
||||
try {
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) {
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
ClassLoader cl = helper.getURLClassLoader(codebases);
|
||||
return deserializeObject((byte[])attr.get(), cl);
|
||||
} else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
|
||||
// javaRemoteLocation attribute (RMI stub will be created)
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
// For backward compatibility only
|
||||
return decodeRmiObject(
|
||||
(String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(),
|
||||
(String)attr.get(), codebases);
|
||||
}
|
||||
|
||||
attr = attrs.get(JAVA_ATTRIBUTES[OBJECT_CLASS]);
|
||||
if (attr != null &&
|
||||
(attr.contains(JAVA_OBJECT_CLASSES[REF_OBJECT]) ||
|
||||
attr.contains(JAVA_OBJECT_CLASSES_LOWER[REF_OBJECT]))) {
|
||||
return decodeReference(attrs, codebases);
|
||||
}
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Reference object into several LDAP attributes.
|
||||
*
|
||||
* A Reference is stored as into the following attributes:
|
||||
* javaClassName
|
||||
* value: Reference.getClassName();
|
||||
* javaFactory
|
||||
* value: Reference.getFactoryClassName();
|
||||
* javaCodeBase
|
||||
* value: Reference.getFactoryClassLocation();
|
||||
* javaReferenceAddress
|
||||
* value: #0#typeA#valA
|
||||
* value: #1#typeB#valB
|
||||
* value: #2#typeC##[serialized RefAddr C]
|
||||
* value: #3#typeD#valD
|
||||
*
|
||||
* where
|
||||
* - the first character denotes the separator
|
||||
* - the number following the first separator denotes the position
|
||||
* of the RefAddr within the Reference
|
||||
* - "typeA" is RefAddr.getType()
|
||||
* - ## denotes that the Base64-encoded form of the non-StringRefAddr
|
||||
* is to follow; otherwise the value that follows is
|
||||
* StringRefAddr.getContents()
|
||||
*
|
||||
* The default separator is the hash character (#).
|
||||
* May provide property for this in future.
|
||||
*/
|
||||
|
||||
private static Attributes encodeReference(char separator,
|
||||
Reference ref, Attributes attrs, Object orig)
|
||||
throws NamingException {
|
||||
|
||||
if (ref == null)
|
||||
return attrs;
|
||||
|
||||
String s;
|
||||
|
||||
if ((s = ref.getClassName()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CLASSNAME], s));
|
||||
}
|
||||
|
||||
if ((s = ref.getFactoryClassName()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[FACTORY], s));
|
||||
}
|
||||
|
||||
if ((s = ref.getFactoryClassLocation()) != null) {
|
||||
attrs.put(new BasicAttribute(JAVA_ATTRIBUTES[CODEBASE], s));
|
||||
}
|
||||
|
||||
// Get original object's types if caller has not explicitly
|
||||
// specified other type names
|
||||
if (orig != null && attrs.get(JAVA_ATTRIBUTES[TYPENAME]) != null) {
|
||||
Attribute tAttr =
|
||||
LdapCtxFactory.createTypeNameAttr(orig.getClass());
|
||||
if (tAttr != null) {
|
||||
attrs.put(tAttr);
|
||||
}
|
||||
}
|
||||
|
||||
int count = ref.size();
|
||||
|
||||
if (count > 0) {
|
||||
|
||||
Attribute refAttr = new BasicAttribute(JAVA_ATTRIBUTES[REF_ADDR]);
|
||||
RefAddr refAddr;
|
||||
BASE64Encoder encoder = null;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
refAddr = ref.get(i);
|
||||
|
||||
if (refAddr instanceof StringRefAddr) {
|
||||
refAttr.add(""+ separator + i +
|
||||
separator + refAddr.getType() +
|
||||
separator + refAddr.getContent());
|
||||
} else {
|
||||
if (encoder == null)
|
||||
encoder = new BASE64Encoder();
|
||||
|
||||
refAttr.add(""+ separator + i +
|
||||
separator + refAddr.getType() +
|
||||
separator + separator +
|
||||
encoder.encodeBuffer(serializeObject(refAddr)));
|
||||
}
|
||||
}
|
||||
attrs.put(refAttr);
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/*
|
||||
* A RMI object is stored in the directory as
|
||||
* javaClassName
|
||||
* value: Object.getClass();
|
||||
* javaRemoteLocation
|
||||
* value: URL of RMI object (accessed through the RMI Registry)
|
||||
* javaCodebase:
|
||||
* value: URL of codebase of where to find classes for object
|
||||
*
|
||||
* Return the RMI Location URL itself. This will be turned into
|
||||
* an RMI object when getObjectInstance() is called on it.
|
||||
* %%% Ignore codebase for now. Depend on RMI registry to send code.-RL
|
||||
* @deprecated For backward compatibility only
|
||||
*/
|
||||
private static Object decodeRmiObject(String className,
|
||||
String rmiName, String[] codebases) throws NamingException {
|
||||
return new Reference(className, new StringRefAddr("URL", rmiName));
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore a Reference object from several LDAP attributes
|
||||
*/
|
||||
private static Reference decodeReference(Attributes attrs,
|
||||
String[] codebases) throws NamingException, IOException {
|
||||
|
||||
Attribute attr;
|
||||
String className;
|
||||
String factory = null;
|
||||
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[CLASSNAME])) != null) {
|
||||
className = (String)attr.get();
|
||||
} else {
|
||||
throw new InvalidAttributesException(JAVA_ATTRIBUTES[CLASSNAME] +
|
||||
" attribute is required");
|
||||
}
|
||||
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[FACTORY])) != null) {
|
||||
factory = (String)attr.get();
|
||||
}
|
||||
|
||||
Reference ref = new Reference(className, factory,
|
||||
(codebases != null? codebases[0] : null));
|
||||
|
||||
/*
|
||||
* string encoding of a RefAddr is either:
|
||||
*
|
||||
* #posn#<type>#<address>
|
||||
* or
|
||||
* #posn#<type>##<base64-encoded address>
|
||||
*/
|
||||
if ((attr = attrs.get(JAVA_ATTRIBUTES[REF_ADDR])) != null) {
|
||||
|
||||
String val, posnStr, type;
|
||||
char separator;
|
||||
int start, sep, posn;
|
||||
BASE64Decoder decoder = null;
|
||||
|
||||
ClassLoader cl = helper.getURLClassLoader(codebases);
|
||||
|
||||
/*
|
||||
* Temporary Vector for decoded RefAddr addresses - used to ensure
|
||||
* unordered addresses are correctly re-ordered.
|
||||
*/
|
||||
Vector<RefAddr> refAddrList = new Vector<>();
|
||||
refAddrList.setSize(attr.size());
|
||||
|
||||
for (NamingEnumeration<?> vals = attr.getAll(); vals.hasMore(); ) {
|
||||
|
||||
val = (String)vals.next();
|
||||
|
||||
if (val.length() == 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - "+
|
||||
"empty attribute value");
|
||||
}
|
||||
// first character denotes encoding separator
|
||||
separator = val.charAt(0);
|
||||
start = 1; // skip over separator
|
||||
|
||||
// extract position within Reference
|
||||
if ((sep = val.indexOf(separator, start)) < 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"separator '" + separator + "'" + "not found");
|
||||
}
|
||||
if ((posnStr = val.substring(start, sep)) == null) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"empty RefAddr position");
|
||||
}
|
||||
try {
|
||||
posn = Integer.parseInt(posnStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"RefAddr position not an integer");
|
||||
}
|
||||
start = sep + 1; // skip over position and trailing separator
|
||||
|
||||
// extract type
|
||||
if ((sep = val.indexOf(separator, start)) < 0) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"RefAddr type not found");
|
||||
}
|
||||
if ((type = val.substring(start, sep)) == null) {
|
||||
throw new InvalidAttributeValueException(
|
||||
"malformed " + JAVA_ATTRIBUTES[REF_ADDR] + " attribute - " +
|
||||
"empty RefAddr type");
|
||||
}
|
||||
start = sep + 1; // skip over type and trailing separator
|
||||
|
||||
// extract content
|
||||
if (start == val.length()) {
|
||||
// Empty content
|
||||
refAddrList.setElementAt(new StringRefAddr(type, null), posn);
|
||||
} else if (val.charAt(start) == separator) {
|
||||
// Check if deserialization of binary RefAddr is allowed from
|
||||
// 'javaReferenceAddress' LDAP attribute.
|
||||
if (!VersionHelper12.isSerialDataAllowed()) {
|
||||
throw new NamingException("Object deserialization is not allowed");
|
||||
}
|
||||
|
||||
// Double separators indicate a non-StringRefAddr
|
||||
// Content is a Base64-encoded serialized RefAddr
|
||||
|
||||
++start; // skip over consecutive separator
|
||||
// %%% RL: exception if empty after double separator
|
||||
|
||||
if (decoder == null)
|
||||
decoder = new BASE64Decoder();
|
||||
|
||||
RefAddr ra = (RefAddr)
|
||||
deserializeObject(
|
||||
decoder.decodeBuffer(val.substring(start)),
|
||||
cl);
|
||||
|
||||
refAddrList.setElementAt(ra, posn);
|
||||
} else {
|
||||
// Single separator indicates a StringRefAddr
|
||||
refAddrList.setElementAt(new StringRefAddr(type,
|
||||
val.substring(start)), posn);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy to real reference
|
||||
for (int i = 0; i < refAddrList.size(); i++) {
|
||||
ref.add(refAddrList.elementAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
return (ref);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize an object into a byte array
|
||||
*/
|
||||
private static byte[] serializeObject(Object obj) throws NamingException {
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
try (ObjectOutputStream serial = new ObjectOutputStream(bytes)) {
|
||||
serial.writeObject(obj);
|
||||
}
|
||||
|
||||
return (bytes.toByteArray());
|
||||
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserializes a byte array into an object.
|
||||
*/
|
||||
private static Object deserializeObject(byte[] obj, ClassLoader cl)
|
||||
throws NamingException {
|
||||
|
||||
try {
|
||||
// Create ObjectInputStream for deserialization
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(obj);
|
||||
try (ObjectInputStream deserial = cl == null ?
|
||||
new ObjectInputStream(bytes) :
|
||||
new LoaderInputStream(bytes, cl)) {
|
||||
return deserial.readObject();
|
||||
} catch (ClassNotFoundException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attributes to bind given an object and its attributes.
|
||||
*/
|
||||
static Attributes determineBindAttrs(
|
||||
char separator, Object obj, Attributes attrs, boolean cloned,
|
||||
Name name, Context ctx, Hashtable<?,?> env)
|
||||
throws NamingException {
|
||||
|
||||
// Call state factories to convert object and attrs
|
||||
DirStateFactory.Result res =
|
||||
DirectoryManager.getStateToBind(obj, name, ctx, env, attrs);
|
||||
obj = res.getObject();
|
||||
attrs = res.getAttributes();
|
||||
|
||||
// We're only storing attributes; no further processing required
|
||||
if (obj == null) {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
//if object to be bound is a DirContext extract its attributes
|
||||
if ((attrs == null) && (obj instanceof DirContext)) {
|
||||
cloned = true;
|
||||
attrs = ((DirContext)obj).getAttributes("");
|
||||
}
|
||||
|
||||
boolean ocNeedsCloning = false;
|
||||
|
||||
// Create "objectClass" attribute
|
||||
Attribute objectClass;
|
||||
if (attrs == null || attrs.size() == 0) {
|
||||
attrs = new BasicAttributes(LdapClient.caseIgnore);
|
||||
cloned = true;
|
||||
|
||||
// No objectclasses supplied, use "top" to start
|
||||
objectClass = new BasicAttribute("objectClass", "top");
|
||||
|
||||
} else {
|
||||
// Get existing objectclass attribute
|
||||
objectClass = attrs.get("objectClass");
|
||||
if (objectClass == null && !attrs.isCaseIgnored()) {
|
||||
// %%% workaround
|
||||
objectClass = attrs.get("objectclass");
|
||||
}
|
||||
|
||||
// No objectclasses supplied, use "top" to start
|
||||
if (objectClass == null) {
|
||||
objectClass = new BasicAttribute("objectClass", "top");
|
||||
} else if (ocNeedsCloning || !cloned) {
|
||||
objectClass = (Attribute)objectClass.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// convert the supplied object into LDAP attributes
|
||||
attrs = encodeObject(separator, obj, attrs, objectClass, cloned);
|
||||
|
||||
// System.err.println("Determined: " + attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* An ObjectInputStream that uses a class loader to find classes.
|
||||
*/
|
||||
private static final class LoaderInputStream extends ObjectInputStream {
|
||||
private ClassLoader classLoader;
|
||||
|
||||
LoaderInputStream(InputStream in, ClassLoader cl) throws IOException {
|
||||
super(in);
|
||||
classLoader = cl;
|
||||
}
|
||||
|
||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws
|
||||
IOException, ClassNotFoundException {
|
||||
try {
|
||||
// %%% Should use Class.forName(desc.getName(), false, classLoader);
|
||||
// except we can't because that is only available on JDK1.2
|
||||
return classLoader.loadClass(desc.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
return super.resolveClass(desc);
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> resolveProxyClass(String[] interfaces) throws
|
||||
IOException, ClassNotFoundException {
|
||||
ClassLoader nonPublicLoader = null;
|
||||
boolean hasNonPublicInterface = false;
|
||||
|
||||
// define proxy in class loader of non-public interface(s), if any
|
||||
Class<?>[] classObjs = new Class<?>[interfaces.length];
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class<?> cl = Class.forName(interfaces[i], false, classLoader);
|
||||
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
|
||||
if (hasNonPublicInterface) {
|
||||
if (nonPublicLoader != cl.getClassLoader()) {
|
||||
throw new IllegalAccessError(
|
||||
"conflicting non-public interface class loaders");
|
||||
}
|
||||
} else {
|
||||
nonPublicLoader = cl.getClassLoader();
|
||||
hasNonPublicInterface = true;
|
||||
}
|
||||
}
|
||||
classObjs[i] = cl;
|
||||
}
|
||||
try {
|
||||
return Proxy.getProxyClass(hasNonPublicInterface ?
|
||||
nonPublicLoader : classLoader, classObjs);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ClassNotFoundException(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
161
jdkSrc/jdk8/com/sun/jndi/ldap/PersistentSearchControl.java
Normal file
161
jdkSrc/jdk8/com/sun/jndi/ldap/PersistentSearchControl.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Request Control for the persistent search
|
||||
* mechanism as defined in
|
||||
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapext-psearch-02.txt">draft-ietf-ldapext-psearch-02.txt</a>.
|
||||
*
|
||||
* The control's value has the following ASN.1 definition:
|
||||
* <pre>
|
||||
*
|
||||
* PersistentSearch ::= SEQUENCE {
|
||||
* changeTypes INTEGER,
|
||||
* changesOnly BOOLEAN,
|
||||
* returnECs BOOLEAN
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see EntryChangeResponseControl
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class PersistentSearchControl extends BasicControl {
|
||||
|
||||
/**
|
||||
* The persistent search control's assigned object identifier
|
||||
* is 2.16.840.1.113730.3.4.3.
|
||||
*/
|
||||
public static final String OID = "2.16.840.1.113730.3.4.3";
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been added.
|
||||
*/
|
||||
public static final int ADD = 1;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been deleted.
|
||||
*/
|
||||
public static final int DELETE = 2;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been modified.
|
||||
*/
|
||||
public static final int MODIFY = 4;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been renamed.
|
||||
*/
|
||||
public static final int RENAME = 8;
|
||||
|
||||
/**
|
||||
* Indicates interest in entries which have been added, deleted,
|
||||
* modified or renamed.
|
||||
*/
|
||||
public static final int ANY = ADD | DELETE | MODIFY | RENAME;
|
||||
|
||||
/**
|
||||
* The change types of interest. All changes, by default.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private int changeTypes = ANY;
|
||||
|
||||
/**
|
||||
* Return original entries and changed entries or only changed entries.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private boolean changesOnly = false;
|
||||
|
||||
/**
|
||||
* Return entry change controls.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private boolean returnControls = true;
|
||||
|
||||
private static final long serialVersionUID = 6335140491154854116L;
|
||||
|
||||
/**
|
||||
* Constructs a persistent search non-critical control.
|
||||
* The original entries, any changed entries (additions,
|
||||
* deletions, modifications or renames) and entry change
|
||||
* controls are requested.
|
||||
*
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
public PersistentSearchControl() throws IOException {
|
||||
super(OID);
|
||||
super.value = setEncodedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a persistent search control.
|
||||
*
|
||||
* @param changeTypes The change types of interest.
|
||||
* @param changesOnly Return original entries and changed entries
|
||||
* or only the changed entries.
|
||||
* @param returnControls Return entry change controls.
|
||||
* @param criticality The control's criticality.
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
public PersistentSearchControl(int changeTypes, boolean changesOnly,
|
||||
boolean returnControls, boolean criticality) throws IOException {
|
||||
|
||||
super(OID, criticality, null);
|
||||
this.changeTypes = changeTypes;
|
||||
this.changesOnly = changesOnly;
|
||||
this.returnControls = returnControls;
|
||||
super.value = setEncodedValue();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the ASN.1 BER encoded value of the persistent search control.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the control's value. It does not include the controls OID or criticality.
|
||||
*
|
||||
* @return A possibly null byte array representing the ASN.1 BER encoded
|
||||
* value of the LDAP persistent search control.
|
||||
* @exception IOException If a BER encoding error occurs.
|
||||
*/
|
||||
private byte[] setEncodedValue() throws IOException {
|
||||
|
||||
// build the ASN.1 encoding
|
||||
BerEncoder ber = new BerEncoder(32);
|
||||
|
||||
ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
|
||||
ber.encodeInt(changeTypes);
|
||||
ber.encodeBoolean(changesOnly);
|
||||
ber.encodeBoolean(returnControls);
|
||||
ber.endSeq();
|
||||
|
||||
return ber.getTrimmedBuf();
|
||||
}
|
||||
}
|
||||
32
jdkSrc/jdk8/com/sun/jndi/ldap/ReferralEnumeration.java
Normal file
32
jdkSrc/jdk8/com/sun/jndi/ldap/ReferralEnumeration.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.NamingEnumeration;
|
||||
|
||||
interface ReferralEnumeration<T> extends NamingEnumeration<T> {
|
||||
void appendUnprocessedReferrals(LdapReferralException ex);
|
||||
}
|
||||
47
jdkSrc/jdk8/com/sun/jndi/ldap/SearchResultWithControls.java
Normal file
47
jdkSrc/jdk8/com/sun/jndi/ldap/SearchResultWithControls.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.ldap;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.ldap.*;
|
||||
|
||||
class SearchResultWithControls extends SearchResult implements HasControls {
|
||||
private Control[] controls;
|
||||
|
||||
public SearchResultWithControls(String name, Object obj, Attributes attrs,
|
||||
boolean isRelative, Control[] controls) {
|
||||
|
||||
super(name, obj, attrs, isRelative);
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 8476983938747908202L;
|
||||
}
|
||||
310
jdkSrc/jdk8/com/sun/jndi/ldap/ServiceLocator.java
Normal file
310
jdkSrc/jdk8/com/sun/jndi/ldap/ServiceLocator.java
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, 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.ldap;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.directory.*;
|
||||
import javax.naming.spi.NamingManager;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import javax.naming.ldap.Rdn;
|
||||
|
||||
/**
|
||||
* This class discovers the location of LDAP services by querying DNS.
|
||||
* See http://www.ietf.org/internet-drafts/draft-ietf-ldapext-locate-07.txt
|
||||
*/
|
||||
|
||||
class ServiceLocator {
|
||||
|
||||
private static final String SRV_RR = "SRV";
|
||||
|
||||
private static final String[] SRV_RR_ATTR = new String[]{SRV_RR};
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
private ServiceLocator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a distinguished name (RFC 2253) to a fully qualified domain name.
|
||||
* Processes a sequence of RDNs having a DC attribute.
|
||||
* The special RDN "DC=." denotes the root of the domain tree.
|
||||
* Multi-valued RDNs, non-DC attributes, binary-valued attributes and the
|
||||
* RDN "DC=." all reset the domain name and processing continues.
|
||||
*
|
||||
* @param dn A string distinguished name (RFC 2253).
|
||||
* @return A domain name or null if none can be derived.
|
||||
* @throw InvalidNameException If the distinugished name is invalid.
|
||||
*/
|
||||
static String mapDnToDomainName(String dn) throws InvalidNameException {
|
||||
if (dn == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuffer domain = new StringBuffer();
|
||||
LdapName ldapName = new LdapName(dn);
|
||||
|
||||
// process RDNs left-to-right
|
||||
//List<Rdn> rdnList = ldapName.getRdns();
|
||||
|
||||
List<Rdn> rdnList = ldapName.getRdns();
|
||||
for (int i = rdnList.size() - 1; i >= 0; i--) {
|
||||
//Rdn rdn = rdnList.get(i);
|
||||
Rdn rdn = rdnList.get(i);
|
||||
|
||||
// single-valued RDN with a DC attribute
|
||||
if ((rdn.size() == 1) &&
|
||||
("dc".equalsIgnoreCase(rdn.getType()) )) {
|
||||
Object attrval = rdn.getValue();
|
||||
if (attrval instanceof String) {
|
||||
if (attrval.equals(".") ||
|
||||
(domain.length() == 1 && domain.charAt(0) == '.')) {
|
||||
domain.setLength(0); // reset (when current or previous
|
||||
// RDN value is "DC=.")
|
||||
}
|
||||
if (domain.length() > 0) {
|
||||
domain.append('.');
|
||||
}
|
||||
domain.append(attrval);
|
||||
} else {
|
||||
domain.setLength(0); // reset (when binary-valued attribute)
|
||||
}
|
||||
} else {
|
||||
domain.setLength(0); // reset (when multi-valued RDN or non-DC)
|
||||
}
|
||||
}
|
||||
return (domain.length() != 0) ? domain.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the LDAP service for a given domain.
|
||||
* Queries DNS for a list of LDAP Service Location Records (SRV) for a
|
||||
* given domain name.
|
||||
*
|
||||
* @param domainName A string domain name.
|
||||
* @param environment The possibly null environment of the context.
|
||||
* @return An ordered list of hostports for the LDAP service or null if
|
||||
* the service has not been located.
|
||||
*/
|
||||
static String[] getLdapService(String domainName, Map<?,?> environment) {
|
||||
if (environment instanceof Hashtable) {
|
||||
return getLdapService(domainName, (Hashtable)environment);
|
||||
}
|
||||
return getLdapService(domainName, new Hashtable<>(environment));
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the LDAP service for a given domain.
|
||||
* Queries DNS for a list of LDAP Service Location Records (SRV) for a
|
||||
* given domain name.
|
||||
*
|
||||
* @param domainName A string domain name.
|
||||
* @param environment The possibly null environment of the context.
|
||||
* @return An ordered list of hostports for the LDAP service or null if
|
||||
* the service has not been located.
|
||||
*/
|
||||
static String[] getLdapService(String domainName, Hashtable<?,?> environment) {
|
||||
|
||||
if (domainName == null || domainName.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String dnsUrl = "dns:///_ldap._tcp." + domainName;
|
||||
String[] hostports = null;
|
||||
|
||||
try {
|
||||
// Create the DNS context using NamingManager rather than using
|
||||
// the initial context constructor. This avoids having the initial
|
||||
// context constructor call itself (when processing the URL
|
||||
// argument in the getAttributes call).
|
||||
Context ctx = NamingManager.getURLContext("dns", environment);
|
||||
if (!(ctx instanceof DirContext)) {
|
||||
return null; // cannot create a DNS context
|
||||
}
|
||||
Attributes attrs =
|
||||
((DirContext)ctx).getAttributes(dnsUrl, SRV_RR_ATTR);
|
||||
Attribute attr;
|
||||
|
||||
if (attrs != null && ((attr = attrs.get(SRV_RR)) != null)) {
|
||||
int numValues = attr.size();
|
||||
int numRecords = 0;
|
||||
SrvRecord[] srvRecords = new SrvRecord[numValues];
|
||||
|
||||
// create the service records
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < numValues) {
|
||||
try {
|
||||
srvRecords[j] = new SrvRecord((String) attr.get(i));
|
||||
j++;
|
||||
} catch (Exception e) {
|
||||
// ignore bad value
|
||||
}
|
||||
i++;
|
||||
}
|
||||
numRecords = j;
|
||||
|
||||
// trim
|
||||
if (numRecords < numValues) {
|
||||
SrvRecord[] trimmed = new SrvRecord[numRecords];
|
||||
System.arraycopy(srvRecords, 0, trimmed, 0, numRecords);
|
||||
srvRecords = trimmed;
|
||||
}
|
||||
|
||||
// Sort the service records in ascending order of their
|
||||
// priority value. For records with equal priority, move
|
||||
// those with weight 0 to the top of the list.
|
||||
if (numRecords > 1) {
|
||||
Arrays.sort(srvRecords);
|
||||
}
|
||||
|
||||
// extract the host and port number from each service record
|
||||
hostports = extractHostports(srvRecords);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
// ignore
|
||||
}
|
||||
return hostports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract hosts and port numbers from a list of SRV records.
|
||||
* An array of hostports is returned or null if none were found.
|
||||
*/
|
||||
private static String[] extractHostports(SrvRecord[] srvRecords) {
|
||||
String[] hostports = null;
|
||||
|
||||
int head = 0;
|
||||
int tail = 0;
|
||||
int sublistLength = 0;
|
||||
int k = 0;
|
||||
for (int i = 0; i < srvRecords.length; i++) {
|
||||
if (hostports == null) {
|
||||
hostports = new String[srvRecords.length];
|
||||
}
|
||||
// find the head and tail of the list of records having the same
|
||||
// priority value.
|
||||
head = i;
|
||||
while (i < srvRecords.length - 1 &&
|
||||
srvRecords[i].priority == srvRecords[i + 1].priority) {
|
||||
i++;
|
||||
}
|
||||
tail = i;
|
||||
|
||||
// select hostports from the sublist
|
||||
sublistLength = (tail - head) + 1;
|
||||
for (int j = 0; j < sublistLength; j++) {
|
||||
hostports[k++] = selectHostport(srvRecords, head, tail);
|
||||
}
|
||||
}
|
||||
return hostports;
|
||||
}
|
||||
|
||||
/*
|
||||
* Randomly select a service record in the range [head, tail] and return
|
||||
* its hostport value. Follows the algorithm in RFC 2782.
|
||||
*/
|
||||
private static String selectHostport(SrvRecord[] srvRecords, int head,
|
||||
int tail) {
|
||||
if (head == tail) {
|
||||
return srvRecords[head].hostport;
|
||||
}
|
||||
|
||||
// compute the running sum for records between head and tail
|
||||
int sum = 0;
|
||||
for (int i = head; i <= tail; i++) {
|
||||
if (srvRecords[i] != null) {
|
||||
sum += srvRecords[i].weight;
|
||||
srvRecords[i].sum = sum;
|
||||
}
|
||||
}
|
||||
String hostport = null;
|
||||
|
||||
// If all records have zero weight, select first available one;
|
||||
// otherwise, randomly select a record according to its weight
|
||||
int target = (sum == 0 ? 0 : random.nextInt(sum + 1));
|
||||
for (int i = head; i <= tail; i++) {
|
||||
if (srvRecords[i] != null && srvRecords[i].sum >= target) {
|
||||
hostport = srvRecords[i].hostport;
|
||||
srvRecords[i] = null; // make this record unavailable
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hostport;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds a DNS service (SRV) record.
|
||||
* See http://www.ietf.org/rfc/rfc2782.txt
|
||||
*/
|
||||
|
||||
static class SrvRecord implements Comparable<SrvRecord> {
|
||||
|
||||
int priority;
|
||||
int weight;
|
||||
int sum;
|
||||
String hostport;
|
||||
|
||||
/**
|
||||
* Creates a service record object from a string record.
|
||||
* DNS supplies the string record in the following format:
|
||||
* <pre>
|
||||
* <Priority> " " <Weight> " " <Port> " " <Host>
|
||||
* </pre>
|
||||
*/
|
||||
SrvRecord(String srvRecord) throws Exception {
|
||||
StringTokenizer tokenizer = new StringTokenizer(srvRecord, " ");
|
||||
String port;
|
||||
|
||||
if (tokenizer.countTokens() == 4) {
|
||||
priority = Integer.parseInt(tokenizer.nextToken());
|
||||
weight = Integer.parseInt(tokenizer.nextToken());
|
||||
port = tokenizer.nextToken();
|
||||
hostport = tokenizer.nextToken() + ":" + port;
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort records in ascending order of priority value. For records with
|
||||
* equal priority move those with weight 0 to the top of the list.
|
||||
*/
|
||||
public int compareTo(SrvRecord that) {
|
||||
if (priority > that.priority) {
|
||||
return 1; // this > that
|
||||
} else if (priority < that.priority) {
|
||||
return -1; // this < that
|
||||
} else if (weight == 0 && that.weight != 0) {
|
||||
return -1; // this < that
|
||||
} else if (weight != 0 && that.weight == 0) {
|
||||
return 1; // this > that
|
||||
} else {
|
||||
return 0; // this == that
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
jdkSrc/jdk8/com/sun/jndi/ldap/SimpleClientId.java
Normal file
100
jdkSrc/jdk8/com/sun/jndi/ldap/SimpleClientId.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, 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.ldap;
|
||||
|
||||
import java.util.Arrays; // JDK1.2
|
||||
import java.io.OutputStream;
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
/**
|
||||
* Represents the identity of a 'simple' authenticated LDAP connection.
|
||||
* In addition to ClientId information, this class contains also the
|
||||
* username and password.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
class SimpleClientId extends ClientId {
|
||||
final private String username;
|
||||
final private Object passwd;
|
||||
final private int myHash;
|
||||
|
||||
SimpleClientId(int version, String hostname, int port,
|
||||
String protocol, Control[] bindCtls, OutputStream trace,
|
||||
String socketFactory, String username, Object passwd) {
|
||||
|
||||
super(version, hostname, port, protocol, bindCtls, trace,
|
||||
socketFactory);
|
||||
|
||||
this.username = username;
|
||||
int pwdHashCode = 0;
|
||||
if (passwd == null) {
|
||||
this.passwd = null;
|
||||
} else if (passwd instanceof byte[]) {
|
||||
this.passwd = ((byte[])passwd).clone();
|
||||
pwdHashCode = Arrays.hashCode((byte[])passwd);
|
||||
} else if (passwd instanceof char[]) {
|
||||
this.passwd = ((char[])passwd).clone();
|
||||
pwdHashCode = Arrays.hashCode((char[])passwd);
|
||||
} else {
|
||||
this.passwd = passwd;
|
||||
pwdHashCode = passwd.hashCode();
|
||||
}
|
||||
|
||||
myHash = super.hashCode()
|
||||
^ (username != null ? username.hashCode() : 0)
|
||||
^ pwdHashCode;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !(obj instanceof SimpleClientId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SimpleClientId other = (SimpleClientId)obj;
|
||||
|
||||
return super.equals(obj)
|
||||
&& (username == other.username // null OK
|
||||
|| (username != null && username.equals(other.username)))
|
||||
&& ((passwd == other.passwd) // null OK
|
||||
|| (passwd != null && other.passwd != null
|
||||
&& (((passwd instanceof String) && passwd.equals(other.passwd))
|
||||
|| ((passwd instanceof byte[])
|
||||
&& (other.passwd instanceof byte[])
|
||||
&& Arrays.equals((byte[])passwd, (byte[])other.passwd))
|
||||
|| ((passwd instanceof char[])
|
||||
&& (other.passwd instanceof char[])
|
||||
&& Arrays.equals((char[])passwd, (char[])other.passwd)))));
|
||||
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myHash;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + ":" + username; // omit password for security
|
||||
}
|
||||
}
|
||||
115
jdkSrc/jdk8/com/sun/jndi/ldap/UnsolicitedResponseImpl.java
Normal file
115
jdkSrc/jdk8/com/sun/jndi/ldap/UnsolicitedResponseImpl.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import javax.naming.ldap.UnsolicitedNotification;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.ldap.Control;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A concrete implementation of an UnsolicitedNotification.
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class UnsolicitedResponseImpl implements UnsolicitedNotification {
|
||||
private String oid;
|
||||
private String[] referrals;
|
||||
private byte[] extensionValue;
|
||||
private NamingException exception;
|
||||
private Control[] controls;
|
||||
|
||||
UnsolicitedResponseImpl(String oid, byte[] berVal, Vector<Vector<String>> ref,
|
||||
int status, String msg, String matchedDN, Control[] controls) {
|
||||
this.oid = oid;
|
||||
this.extensionValue = berVal;
|
||||
|
||||
if (ref != null && ref.size() > 0) {
|
||||
int len = ref.size();
|
||||
referrals = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
// ref is a list of single-String Vectors
|
||||
referrals[i] = ref.elementAt(i).elementAt(0);
|
||||
}
|
||||
}
|
||||
exception = LdapCtx.mapErrorCode(status, msg);
|
||||
// matchedDN ignored for now; could be used to set resolvedName
|
||||
// exception.setResolvedName(new CompositeName().add(matchedDN));
|
||||
|
||||
this.controls = controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object identifier of the response.
|
||||
*
|
||||
* @return A possibly null object identifier string representing the LDAP
|
||||
* <tt>ExtendedResponse.responseName</tt> component.
|
||||
*/
|
||||
public String getID() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ASN.1 BER encoded value of the LDAP extended operation
|
||||
* response. Null is returned if the value is absent from the response
|
||||
* sent by the LDAP server.
|
||||
* The result is the raw BER bytes including the tag and length of
|
||||
* the response value. It does not include the response OID.
|
||||
*
|
||||
* @return A possibly null byte array representing the ASN.1 BER encoded
|
||||
* contents of the LDAP <tt>ExtendedResponse.response</tt>
|
||||
* component.
|
||||
*/
|
||||
public byte[] getEncodedValue() {
|
||||
return extensionValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the referral(s) sent by the server.
|
||||
*
|
||||
* @return A possibly null array of referrals, each of which is represented
|
||||
* by a URL string. If null, no referral was sent by the server.
|
||||
*/
|
||||
public String[] getReferrals() {
|
||||
return referrals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the exception as constructed using information
|
||||
* sent by the server.
|
||||
* @return A possibly null exception as constructed using information
|
||||
* sent by the server. If null, a "success" status was indicated by
|
||||
* the server.
|
||||
*/
|
||||
public NamingException getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public Control[] getControls() throws NamingException {
|
||||
return controls;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 5913778898401784775L;
|
||||
}
|
||||
78
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper.java
Normal file
78
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
abstract class VersionHelper {
|
||||
|
||||
private static VersionHelper helper = null;
|
||||
|
||||
VersionHelper() {} // Disallow anyone from creating one of these.
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName("java.net.URLClassLoader"); // 1.2 test
|
||||
Class.forName("java.security.PrivilegedAction"); // 1.2 test
|
||||
helper = (VersionHelper)
|
||||
Class.forName(
|
||||
"com.sun.jndi.ldap.VersionHelper12").newInstance();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
// Use 1.1 helper if 1.2 test fails, or if we cannot create 1.2 helper
|
||||
if (helper == null) {
|
||||
try {
|
||||
helper = (VersionHelper)
|
||||
Class.forName(
|
||||
"com.sun.jndi.ldap.VersionHelper11").newInstance();
|
||||
} catch (Exception e) {
|
||||
// should never happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VersionHelper getVersionHelper() {
|
||||
return helper;
|
||||
}
|
||||
|
||||
abstract ClassLoader getURLClassLoader(String[] url)
|
||||
throws MalformedURLException;
|
||||
|
||||
|
||||
static protected URL[] getUrlArray(String[] url) throws MalformedURLException {
|
||||
URL[] urlArray = new URL[url.length];
|
||||
for (int i = 0; i < urlArray.length; i++) {
|
||||
urlArray[i] = new URL(url[i]);
|
||||
}
|
||||
return urlArray;
|
||||
}
|
||||
|
||||
abstract Class<?> loadClass(String className) throws ClassNotFoundException;
|
||||
|
||||
abstract Thread createThread(Runnable r);
|
||||
}
|
||||
128
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper12.java
Normal file
128
jdkSrc/jdk8/com/sun/jndi/ldap/VersionHelper12.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.ldap;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.misc.SharedSecrets;
|
||||
|
||||
final class VersionHelper12 extends VersionHelper {
|
||||
|
||||
// System property to control whether classes may be loaded from an
|
||||
// arbitrary URL code base.
|
||||
private static final String TRUST_URL_CODEBASE_PROPERTY =
|
||||
"com.sun.jndi.ldap.object.trustURLCodebase";
|
||||
|
||||
// System property to control whether classes are allowed to be loaded from
|
||||
// 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' attributes.
|
||||
private static final String TRUST_SERIAL_DATA_PROPERTY =
|
||||
"com.sun.jndi.ldap.object.trustSerialData";
|
||||
|
||||
/**
|
||||
* Determines whether objects may be deserialized or reconstructed from a content of
|
||||
* 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' LDAP attributes.
|
||||
*/
|
||||
private static final boolean trustSerialData;
|
||||
|
||||
// Determine whether classes may be loaded from an arbitrary URL code base.
|
||||
private static final boolean trustURLCodebase;
|
||||
|
||||
static {
|
||||
String trust = getPrivilegedProperty(TRUST_URL_CODEBASE_PROPERTY, "false");
|
||||
trustURLCodebase = "true".equalsIgnoreCase(trust);
|
||||
String trustSDString = getPrivilegedProperty(TRUST_SERIAL_DATA_PROPERTY, "false");
|
||||
trustSerialData = "true".equalsIgnoreCase(trustSDString);
|
||||
}
|
||||
|
||||
private static String getPrivilegedProperty(String propertyName, String defaultVal) {
|
||||
PrivilegedAction<String> action = () -> System.getProperty(propertyName, defaultVal);
|
||||
if (System.getSecurityManager() == null) {
|
||||
return action.run();
|
||||
} else {
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
}
|
||||
|
||||
VersionHelper12() {} // Disallow external from creating one of these.
|
||||
|
||||
/**
|
||||
* Returns true if deserialization or reconstruction of objects from
|
||||
* 'javaSerializedData', 'javaRemoteLocation' and 'javaReferenceAddress'
|
||||
* LDAP attributes is allowed.
|
||||
*
|
||||
* @return true if deserialization is allowed; false - otherwise
|
||||
*/
|
||||
public static boolean isSerialDataAllowed() {
|
||||
return trustSerialData;
|
||||
}
|
||||
|
||||
ClassLoader getURLClassLoader(String[] url)
|
||||
throws MalformedURLException {
|
||||
ClassLoader parent = getContextClassLoader();
|
||||
/*
|
||||
* Classes may only be loaded from an arbitrary URL code base when
|
||||
* the system property com.sun.jndi.ldap.object.trustURLCodebase
|
||||
* has been set to "true".
|
||||
*/
|
||||
if (url != null && trustURLCodebase) {
|
||||
return URLClassLoader.newInstance(getUrlArray(url), parent);
|
||||
} else {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
ClassLoader cl = getContextClassLoader();
|
||||
return Class.forName(className, true, cl);
|
||||
}
|
||||
|
||||
private ClassLoader getContextClassLoader() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Thread createThread(final Runnable r) {
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
// 4290486: doPrivileged is needed to create a thread in
|
||||
// an environment that restricts "modifyThreadGroup".
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<Thread>() {
|
||||
public Thread run() {
|
||||
return SharedSecrets.getJavaLangAccess()
|
||||
.newThreadWithAcc(r, acc);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
471
jdkSrc/jdk8/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java
Normal file
471
jdkSrc/jdk8/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2020, 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.ldap.ext;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import sun.security.util.HostnameChecker;
|
||||
|
||||
import javax.naming.ldap.*;
|
||||
import com.sun.jndi.ldap.Connection;
|
||||
|
||||
/**
|
||||
* This class implements the LDAPv3 Extended Response for StartTLS as
|
||||
* defined in
|
||||
* <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
|
||||
* Access Protocol (v3): Extension for Transport Layer Security</a>
|
||||
*
|
||||
* The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
|
||||
* and no extended response value is defined.
|
||||
*
|
||||
*<p>
|
||||
* The Start TLS extended request and response are used to establish
|
||||
* a TLS connection over the existing LDAP connection associated with
|
||||
* the JNDI context on which <tt>extendedOperation()</tt> is invoked.
|
||||
*
|
||||
* @see StartTlsRequest
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
final public class StartTlsResponseImpl extends StartTlsResponse {
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
/*
|
||||
* The dNSName type in a subjectAltName extension of an X.509 certificate
|
||||
*/
|
||||
private static final int DNSNAME_TYPE = 2;
|
||||
|
||||
/*
|
||||
* The server's hostname.
|
||||
*/
|
||||
private transient String hostname = null;
|
||||
|
||||
/*
|
||||
* The LDAP socket.
|
||||
*/
|
||||
private transient Connection ldapConnection = null;
|
||||
|
||||
/*
|
||||
* The original input stream.
|
||||
*/
|
||||
private transient InputStream originalInputStream = null;
|
||||
|
||||
/*
|
||||
* The original output stream.
|
||||
*/
|
||||
private transient OutputStream originalOutputStream = null;
|
||||
|
||||
/*
|
||||
* The SSL socket.
|
||||
*/
|
||||
private transient SSLSocket sslSocket = null;
|
||||
|
||||
/*
|
||||
* The SSL socket factories.
|
||||
*/
|
||||
private transient SSLSocketFactory defaultFactory = null;
|
||||
private transient SSLSocketFactory currentFactory = null;
|
||||
|
||||
/*
|
||||
* The list of cipher suites to be enabled.
|
||||
*/
|
||||
private transient String[] suites = null;
|
||||
|
||||
/*
|
||||
* The hostname verifier callback.
|
||||
*/
|
||||
private transient HostnameVerifier verifier = null;
|
||||
|
||||
/*
|
||||
* The flag to indicate that the TLS connection is closed.
|
||||
*/
|
||||
private transient boolean isClosed = true;
|
||||
|
||||
private static final long serialVersionUID = -1126624615143411328L;
|
||||
|
||||
// public no-arg constructor required by JDK's Service Provider API.
|
||||
|
||||
public StartTlsResponseImpl() {}
|
||||
|
||||
/**
|
||||
* Overrides the default list of cipher suites enabled for use on the
|
||||
* TLS connection. The cipher suites must have already been listed by
|
||||
* <tt>SSLSocketFactory.getSupportedCipherSuites()</tt> as being supported.
|
||||
* Even if a suite has been enabled, it still might not be used because
|
||||
* the peer does not support it, or because the requisite certificates
|
||||
* (and private keys) are not available.
|
||||
*
|
||||
* @param suites The non-null list of names of all the cipher suites to
|
||||
* enable.
|
||||
* @see #negotiate
|
||||
*/
|
||||
public void setEnabledCipherSuites(String[] suites) {
|
||||
// The impl does accept null suites, although the spec requires
|
||||
// a non-null list.
|
||||
this.suites = suites == null ? null : suites.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default hostname verifier used by <tt>negotiate()</tt>
|
||||
* after the TLS handshake has completed. If
|
||||
* <tt>setHostnameVerifier()</tt> has not been called before
|
||||
* <tt>negotiate()</tt> is invoked, <tt>negotiate()</tt>
|
||||
* will perform a simple case ignore match. If called after
|
||||
* <tt>negotiate()</tt>, this method does not do anything.
|
||||
*
|
||||
* @param verifier The non-null hostname verifier callback.
|
||||
* @see #negotiate
|
||||
*/
|
||||
public void setHostnameVerifier(HostnameVerifier verifier) {
|
||||
this.verifier = verifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negotiates a TLS session using the default SSL socket factory.
|
||||
* <p>
|
||||
* This method is equivalent to <tt>negotiate(null)</tt>.
|
||||
*
|
||||
* @return The negotiated SSL session
|
||||
* @throw IOException If an IO error was encountered while establishing
|
||||
* the TLS session.
|
||||
* @see #setEnabledCipherSuites
|
||||
* @see #setHostnameVerifier
|
||||
*/
|
||||
public SSLSession negotiate() throws IOException {
|
||||
|
||||
return negotiate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negotiates a TLS session using an SSL socket factory.
|
||||
* <p>
|
||||
* Creates an SSL socket using the supplied SSL socket factory and
|
||||
* attaches it to the existing connection. Performs the TLS handshake
|
||||
* and returns the negotiated session information.
|
||||
* <p>
|
||||
* If cipher suites have been set via <tt>setEnabledCipherSuites</tt>
|
||||
* then they are enabled before the TLS handshake begins.
|
||||
* <p>
|
||||
* Hostname verification is performed after the TLS handshake completes.
|
||||
* The default check performs a case insensitive match of the server's
|
||||
* hostname against that in the server's certificate. The server's
|
||||
* hostname is extracted from the subjectAltName in the server's
|
||||
* certificate (if present). Otherwise the value of the common name
|
||||
* attribute of the subject name is used. If a callback has
|
||||
* been set via <tt>setHostnameVerifier</tt> then that verifier is used if
|
||||
* the default check fails.
|
||||
* <p>
|
||||
* If an error occurs then the SSL socket is closed and an IOException
|
||||
* is thrown. The underlying connection remains intact.
|
||||
*
|
||||
* @param factory The possibly null SSL socket factory to use.
|
||||
* If null, the default SSL socket factory is used.
|
||||
* @return The negotiated SSL session
|
||||
* @throw IOException If an IO error was encountered while establishing
|
||||
* the TLS session.
|
||||
* @see #setEnabledCipherSuites
|
||||
* @see #setHostnameVerifier
|
||||
*/
|
||||
public SSLSession negotiate(SSLSocketFactory factory) throws IOException {
|
||||
|
||||
if (isClosed && sslSocket != null) {
|
||||
throw new IOException("TLS connection is closed.");
|
||||
}
|
||||
|
||||
if (factory == null) {
|
||||
factory = getDefaultFactory();
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: About to start handshake");
|
||||
}
|
||||
|
||||
SSLSession sslSession = startHandshake(factory).getSession();
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Completed handshake");
|
||||
}
|
||||
|
||||
SSLPeerUnverifiedException verifExcep = null;
|
||||
try {
|
||||
if (verify(hostname, sslSession)) {
|
||||
isClosed = false;
|
||||
return sslSession;
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
// Save to return the cause
|
||||
verifExcep = e;
|
||||
}
|
||||
if ((verifier != null) &&
|
||||
verifier.verify(hostname, sslSession)) {
|
||||
isClosed = false;
|
||||
return sslSession;
|
||||
}
|
||||
|
||||
// Verification failed
|
||||
close();
|
||||
sslSession.invalidate();
|
||||
if (verifExcep == null) {
|
||||
verifExcep = new SSLPeerUnverifiedException(
|
||||
"hostname of the server '" + hostname +
|
||||
"' does not match the hostname in the " +
|
||||
"server's certificate.");
|
||||
}
|
||||
throw verifExcep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the TLS connection gracefully and reverts back to the underlying
|
||||
* connection.
|
||||
*
|
||||
* @throw IOException If an IO error was encountered while closing the
|
||||
* TLS connection
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: replacing SSL " +
|
||||
"streams with originals");
|
||||
}
|
||||
|
||||
// Replace SSL streams with the original streams
|
||||
ldapConnection.replaceStreams(
|
||||
originalInputStream, originalOutputStream, false);
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: closing SSL Socket");
|
||||
}
|
||||
sslSocket.close();
|
||||
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection for TLS to use. The TLS connection will be attached
|
||||
* to this connection.
|
||||
*
|
||||
* @param ldapConnection The non-null connection to use.
|
||||
* @param hostname The server's hostname. If null, the hostname used to
|
||||
* open the connection will be used instead.
|
||||
*/
|
||||
public void setConnection(Connection ldapConnection, String hostname) {
|
||||
this.ldapConnection = ldapConnection;
|
||||
this.hostname = (hostname == null || hostname.isEmpty())
|
||||
? ldapConnection.host : hostname;
|
||||
originalInputStream = ldapConnection.inStream;
|
||||
originalOutputStream = ldapConnection.outStream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the default SSL socket factory.
|
||||
*
|
||||
* @return The default SSL socket factory.
|
||||
* @throw IOException If TLS is not supported.
|
||||
*/
|
||||
private SSLSocketFactory getDefaultFactory() throws IOException {
|
||||
|
||||
if (defaultFactory != null) {
|
||||
return defaultFactory;
|
||||
}
|
||||
|
||||
return (defaultFactory =
|
||||
(SSLSocketFactory) SSLSocketFactory.getDefault());
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the TLS handshake and manipulate the input and output streams.
|
||||
*
|
||||
* @param factory The SSL socket factory to use.
|
||||
* @return The SSL socket.
|
||||
* @throw IOException If an exception occurred while performing the
|
||||
* TLS handshake.
|
||||
*/
|
||||
private SSLSocket startHandshake(SSLSocketFactory factory)
|
||||
throws IOException {
|
||||
|
||||
if (ldapConnection == null) {
|
||||
throw new IllegalStateException("LDAP connection has not been set."
|
||||
+ " TLS requires an existing LDAP connection.");
|
||||
}
|
||||
|
||||
if (factory != currentFactory) {
|
||||
// Create SSL socket layered over the existing connection
|
||||
sslSocket = (SSLSocket) factory.createSocket(ldapConnection.sock,
|
||||
ldapConnection.host, ldapConnection.port, false);
|
||||
currentFactory = factory;
|
||||
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Created socket : " + sslSocket);
|
||||
}
|
||||
}
|
||||
|
||||
if (suites != null) {
|
||||
sslSocket.setEnabledCipherSuites(suites);
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Enabled cipher suites");
|
||||
}
|
||||
}
|
||||
|
||||
// Connection must be quite for handshake to proceed
|
||||
|
||||
try {
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"StartTLS: Calling sslSocket.startHandshake");
|
||||
}
|
||||
sslSocket.startHandshake();
|
||||
if (debug) {
|
||||
System.out.println(
|
||||
"StartTLS: + Finished sslSocket.startHandshake");
|
||||
}
|
||||
|
||||
// Replace original streams with the new SSL streams
|
||||
ldapConnection.replaceStreams(sslSocket.getInputStream(),
|
||||
sslSocket.getOutputStream(), true);
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Replaced IO Streams");
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
if (debug) {
|
||||
System.out.println("StartTLS: Got IO error during handshake");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
sslSocket.close();
|
||||
isClosed = true;
|
||||
throw e; // pass up exception
|
||||
}
|
||||
|
||||
return sslSocket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the hostname in the server's certificate matches the
|
||||
* hostname of the server.
|
||||
* The server's first certificate is examined. If it has a subjectAltName
|
||||
* that contains a dNSName then that is used as the server's hostname.
|
||||
* The server's hostname may contain a wildcard for its left-most name part.
|
||||
* Otherwise, if the certificate has no subjectAltName then the value of
|
||||
* the common name attribute of the subject name is used.
|
||||
*
|
||||
* @param hostname The hostname of the server.
|
||||
* @param session the SSLSession used on the connection to host.
|
||||
* @return true if the hostname is verified, false otherwise.
|
||||
*/
|
||||
|
||||
private boolean verify(String hostname, SSLSession session)
|
||||
throws SSLPeerUnverifiedException {
|
||||
|
||||
java.security.cert.Certificate[] certs = null;
|
||||
|
||||
// if IPv6 strip off the "[]"
|
||||
if (hostname != null && hostname.startsWith("[") &&
|
||||
hostname.endsWith("]")) {
|
||||
hostname = hostname.substring(1, hostname.length() - 1);
|
||||
}
|
||||
try {
|
||||
HostnameChecker checker = HostnameChecker.getInstance(
|
||||
HostnameChecker.TYPE_LDAP);
|
||||
// Use ciphersuite to determine whether Kerberos is active.
|
||||
if (session.getCipherSuite().startsWith("TLS_KRB5")) {
|
||||
Principal principal = getPeerPrincipal(session);
|
||||
if (!HostnameChecker.match(hostname, principal)) {
|
||||
throw new SSLPeerUnverifiedException(
|
||||
"hostname of the kerberos principal:" + principal +
|
||||
" does not match the hostname:" + hostname);
|
||||
}
|
||||
} else { // X.509
|
||||
|
||||
// get the subject's certificate
|
||||
certs = session.getPeerCertificates();
|
||||
X509Certificate peerCert;
|
||||
if (certs[0] instanceof java.security.cert.X509Certificate) {
|
||||
peerCert = (java.security.cert.X509Certificate) certs[0];
|
||||
} else {
|
||||
throw new SSLPeerUnverifiedException(
|
||||
"Received a non X509Certificate from the server");
|
||||
}
|
||||
checker.match(hostname, peerCert);
|
||||
}
|
||||
|
||||
// no exception means verification passed
|
||||
return true;
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
|
||||
/*
|
||||
* The application may enable an anonymous SSL cipher suite, and
|
||||
* hostname verification is not done for anonymous ciphers
|
||||
*/
|
||||
String cipher = session.getCipherSuite();
|
||||
if (cipher != null && (cipher.indexOf("_anon_") != -1)) {
|
||||
return true;
|
||||
}
|
||||
throw e;
|
||||
} catch (CertificateException e) {
|
||||
|
||||
/*
|
||||
* Pass up the cause of the failure
|
||||
*/
|
||||
throw(SSLPeerUnverifiedException)
|
||||
new SSLPeerUnverifiedException("hostname of the server '" +
|
||||
hostname +
|
||||
"' does not match the hostname in the " +
|
||||
"server's certificate.").initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the peer principal from the session
|
||||
*/
|
||||
private static Principal getPeerPrincipal(SSLSession session)
|
||||
throws SSLPeerUnverifiedException {
|
||||
Principal principal;
|
||||
try {
|
||||
principal = session.getPeerPrincipal();
|
||||
} catch (AbstractMethodError e) {
|
||||
// if the JSSE provider does not support it, return null, since
|
||||
// we need it only for Kerberos.
|
||||
principal = null;
|
||||
}
|
||||
return principal;
|
||||
}
|
||||
}
|
||||
160
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionDesc.java
Normal file
160
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionDesc.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a description of PooledConnection in Connections.
|
||||
* Contains a PooledConnection, its state (busy, idle, expired), and idle time.
|
||||
*
|
||||
* Any access or update to a descriptor's state is synchronized.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class ConnectionDesc {
|
||||
private final static boolean debug = Pool.debug;
|
||||
|
||||
// Package private because used by Pool.showStats()
|
||||
static final byte BUSY = (byte)0;
|
||||
static final byte IDLE = (byte)1;
|
||||
static final byte EXPIRED = (byte)2;
|
||||
|
||||
final private PooledConnection conn;
|
||||
|
||||
private byte state = IDLE; // initial state
|
||||
private long idleSince;
|
||||
private long useCount = 0; // for stats & debugging only
|
||||
|
||||
ConnectionDesc(PooledConnection conn) {
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
ConnectionDesc(PooledConnection conn, boolean use) {
|
||||
this.conn = conn;
|
||||
if (use) {
|
||||
state = BUSY;
|
||||
++useCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Two desc are equal if their PooledConnections are the same.
|
||||
* This is useful when searching for a ConnectionDesc using only its
|
||||
* PooledConnection.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
return obj != null
|
||||
&& obj instanceof ConnectionDesc
|
||||
&& ((ConnectionDesc)obj).conn == conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashcode is that of PooledConnection to facilitate
|
||||
* searching for a ConnectionDesc using only its PooledConnection.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return conn.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the state of a ConnectionDesc from BUSY to IDLE and
|
||||
* records the current time so that we will know how long it has been idle.
|
||||
* @return true if state change occurred.
|
||||
*/
|
||||
synchronized boolean release() {
|
||||
d("release()");
|
||||
if (state == BUSY) {
|
||||
state = IDLE;
|
||||
|
||||
idleSince = System.currentTimeMillis();
|
||||
return true; // Connection released, ready for reuse
|
||||
} else {
|
||||
return false; // Connection wasn't busy to begin with
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If ConnectionDesc is IDLE, change its state to BUSY and return
|
||||
* its connection.
|
||||
*
|
||||
* @return ConnectionDesc's PooledConnection if it was idle; null otherwise.
|
||||
*/
|
||||
synchronized PooledConnection tryUse() {
|
||||
d("tryUse()");
|
||||
|
||||
if (state == IDLE) {
|
||||
state = BUSY;
|
||||
++useCount;
|
||||
return conn;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If ConnectionDesc is IDLE and has expired, close the corresponding
|
||||
* PooledConnection.
|
||||
*
|
||||
* @param threshold a connection that has been idle before this time
|
||||
* have expired.
|
||||
*
|
||||
* @return true if entry is idle and has expired; false otherwise.
|
||||
*/
|
||||
synchronized boolean expire(long threshold) {
|
||||
if (state == IDLE && idleSince < threshold) {
|
||||
|
||||
d("expire(): expired");
|
||||
|
||||
state = EXPIRED;
|
||||
conn.closeConnection(); // Close real connection
|
||||
|
||||
return true; // Expiration successful
|
||||
} else {
|
||||
d("expire(): not expired");
|
||||
return false; // Expiration did not occur
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return conn.toString() + " " +
|
||||
(state == BUSY ? "busy" : (state == IDLE ? "idle" : "expired"));
|
||||
}
|
||||
|
||||
// Used by Pool.showStats()
|
||||
int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Used by Pool.showStats()
|
||||
long getUseCount() {
|
||||
return useCount;
|
||||
}
|
||||
|
||||
private void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println("ConnectionDesc." + msg + " " + toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
391
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Connections.java
Normal file
391
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Connections.java
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
import java.util.ArrayList; // JDK 1.2
|
||||
import java.util.List;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
import javax.naming.CommunicationException;
|
||||
|
||||
/**
|
||||
* Represents a list of PooledConnections (actually, ConnectionDescs) with the
|
||||
* same pool id.
|
||||
* The list starts out with an initial number of connections.
|
||||
* Additional PooledConnections are created lazily upon demand.
|
||||
* The list has a maximum size. When the number of connections
|
||||
* reaches the maximum size, a request for a PooledConnection blocks until
|
||||
* a connection is returned to the list. A maximum size of zero means that
|
||||
* there is no maximum: connection creation will be attempted when
|
||||
* no idle connection is available.
|
||||
*
|
||||
* The list may also have a preferred size. If the current list size
|
||||
* is less than the preferred size, a request for a connection will result in
|
||||
* a PooledConnection being created (even if an idle connection is available).
|
||||
* If the current list size is greater than the preferred size,
|
||||
* a connection being returned to the list will be closed and removed from
|
||||
* the list. A preferred size of zero means that there is no preferred size:
|
||||
* connections are created only when no idle connection is available and
|
||||
* a connection being returned to the list is not closed. Regardless of the
|
||||
* preferred size, connection creation always observes the maximum size:
|
||||
* a connection won't be created if the list size is at or exceeds the
|
||||
* maximum size.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
// Package private: accessed only by Pool
|
||||
final class Connections implements PoolCallback {
|
||||
private static final boolean debug = Pool.debug;
|
||||
private static final boolean trace =
|
||||
com.sun.jndi.ldap.LdapPoolManager.trace;
|
||||
private static final int DEFAULT_SIZE = 10;
|
||||
|
||||
final private int maxSize;
|
||||
final private int prefSize;
|
||||
final private List<ConnectionDesc> conns;
|
||||
|
||||
private boolean closed = false; // Closed for business
|
||||
private Reference<Object> ref; // maintains reference to id to prevent premature GC
|
||||
|
||||
/**
|
||||
* @param id the identity (connection request) of the connections in the list
|
||||
* @param initSize the number of connections to create initially
|
||||
* @param prefSize the preferred size of the pool. The pool will try
|
||||
* to maintain a pool of this size by creating and closing connections
|
||||
* as needed.
|
||||
* @param maxSize the maximum size of the pool. The pool will not exceed
|
||||
* this size. If the pool is at this size, a request for a connection
|
||||
* will block until an idle connection is released to the pool or
|
||||
* when one is removed.
|
||||
* @param factory The factory responsible for creating a connection
|
||||
*/
|
||||
Connections(Object id, int initSize, int prefSize, int maxSize,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
this.maxSize = maxSize;
|
||||
if (maxSize > 0) {
|
||||
// prefSize and initSize cannot exceed specified maxSize
|
||||
this.prefSize = Math.min(prefSize, maxSize);
|
||||
initSize = Math.min(initSize, maxSize);
|
||||
} else {
|
||||
this.prefSize = prefSize;
|
||||
}
|
||||
conns = new ArrayList<>(maxSize > 0 ? maxSize : DEFAULT_SIZE);
|
||||
|
||||
// Maintain soft ref to id so that this Connections' entry in
|
||||
// Pool doesn't get GC'ed prematurely
|
||||
ref = new SoftReference<>(id);
|
||||
|
||||
d("init size=", initSize);
|
||||
d("max size=", maxSize);
|
||||
d("preferred size=", prefSize);
|
||||
|
||||
// Create initial connections
|
||||
PooledConnection conn;
|
||||
for (int i = 0; i < initSize; i++) {
|
||||
conn = factory.createPooledConnection(this);
|
||||
td("Create ", conn ,factory);
|
||||
conns.add(new ConnectionDesc(conn)); // Add new idle conn to pool
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a PooledConnection from this list of connections.
|
||||
* Use an existing one if one is idle, or create one if the list's
|
||||
* max size hasn't been reached. If max size has been reached, wait
|
||||
* for a PooledConnection to be returned, or one to be removed (thus
|
||||
* not reaching the max size any longer).
|
||||
*
|
||||
* @param timeout if > 0, msec to wait until connection is available
|
||||
* @param factory creates the PooledConnection if one needs to be created
|
||||
*
|
||||
* @return A non-null PooledConnection
|
||||
* @throws NamingException PooledConnection cannot be created, because this
|
||||
* thread was interrupted while it waited for an available connection,
|
||||
* or if it timed out while waiting, or the creation of a connection
|
||||
* resulted in an error.
|
||||
*/
|
||||
synchronized PooledConnection get(long timeout,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
PooledConnection conn;
|
||||
long start = (timeout > 0 ? System.currentTimeMillis() : 0);
|
||||
long waittime = timeout;
|
||||
|
||||
d("get(): before");
|
||||
while ((conn = getOrCreateConnection(factory)) == null) {
|
||||
if (timeout > 0 && waittime <= 0) {
|
||||
throw new CommunicationException(
|
||||
"Timeout exceeded while waiting for a connection: " +
|
||||
timeout + "ms");
|
||||
}
|
||||
try {
|
||||
d("get(): waiting");
|
||||
if (waittime > 0) {
|
||||
wait(waittime); // Wait until one is released or removed
|
||||
} else {
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new InterruptedNamingException(
|
||||
"Interrupted while waiting for a connection");
|
||||
}
|
||||
// Check whether we timed out
|
||||
if (timeout > 0) {
|
||||
long now = System.currentTimeMillis();
|
||||
waittime = timeout - (now - start);
|
||||
}
|
||||
}
|
||||
|
||||
d("get(): after");
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an idle connection from this list if one is available.
|
||||
* If none is available, create a new one if maxSize hasn't been reached.
|
||||
* If maxSize has been reached, return null.
|
||||
* Always called from a synchronized method.
|
||||
*/
|
||||
private PooledConnection getOrCreateConnection(
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
int size = conns.size(); // Current number of idle/nonidle conns
|
||||
PooledConnection conn = null;
|
||||
|
||||
if (prefSize <= 0 || size >= prefSize) {
|
||||
// If no prefSize specified, or list size already meets or
|
||||
// exceeds prefSize, then first look for an idle connection
|
||||
ConnectionDesc entry;
|
||||
for (int i = 0; i < size; i++) {
|
||||
entry = conns.get(i);
|
||||
if ((conn = entry.tryUse()) != null) {
|
||||
d("get(): use ", conn);
|
||||
td("Use ", conn);
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if list size already at maxSize specified
|
||||
if (maxSize > 0 && size >= maxSize) {
|
||||
return null; // List size is at limit; cannot create any more
|
||||
}
|
||||
|
||||
conn = factory.createPooledConnection(this);
|
||||
td("Create and use ", conn, factory);
|
||||
conns.add(new ConnectionDesc(conn, true)); // Add new conn to pool
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases connection back into list.
|
||||
* If the list size is below prefSize, the connection may be reused.
|
||||
* If the list size exceeds prefSize, then the connection is closed
|
||||
* and removed from the list.
|
||||
*
|
||||
* public because implemented as part of PoolCallback.
|
||||
*/
|
||||
public synchronized boolean releasePooledConnection(PooledConnection conn) {
|
||||
ConnectionDesc entry;
|
||||
int loc = conns.indexOf(entry=new ConnectionDesc(conn));
|
||||
|
||||
d("release(): ", conn);
|
||||
|
||||
if (loc >= 0) {
|
||||
// Found entry
|
||||
|
||||
if (closed || (prefSize > 0 && conns.size() > prefSize)) {
|
||||
// If list size exceeds prefSize, close connection
|
||||
|
||||
d("release(): closing ", conn);
|
||||
td("Close ", conn);
|
||||
|
||||
// size must be >= 2 so don't worry about empty list
|
||||
conns.remove(entry);
|
||||
conn.closeConnection();
|
||||
|
||||
} else {
|
||||
d("release(): release ", conn);
|
||||
td("Release ", conn);
|
||||
|
||||
// Get ConnectionDesc from list to get correct state info
|
||||
entry = conns.get(loc);
|
||||
// Return connection to list, ready for reuse
|
||||
entry.release();
|
||||
}
|
||||
notifyAll();
|
||||
d("release(): notify");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes PooledConnection from list of connections.
|
||||
* The closing of the connection is separate from this method.
|
||||
* This method is called usually when the caller encouters an error
|
||||
* when using the connection and wants it removed from the pool.
|
||||
*
|
||||
* @return true if conn removed; false if it was not in pool
|
||||
*
|
||||
* public because implemented as part of PoolCallback.
|
||||
*/
|
||||
public synchronized boolean removePooledConnection(PooledConnection conn) {
|
||||
if (conns.remove(new ConnectionDesc(conn))) {
|
||||
d("remove(): ", conn);
|
||||
|
||||
notifyAll();
|
||||
|
||||
d("remove(): notify");
|
||||
td("Remove ", conn);
|
||||
|
||||
if (conns.isEmpty()) {
|
||||
// Remove softref to make pool entry eligible for GC.
|
||||
// Once ref has been removed, it cannot be reinstated.
|
||||
ref = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
d("remove(): not found ", conn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through all entries in list, removes and closes ones that have been
|
||||
* idle before threshold.
|
||||
*
|
||||
* @param threshold an entry idle since this time has expired.
|
||||
* @return true if no more connections in list
|
||||
*/
|
||||
boolean expire(long threshold) {
|
||||
List<ConnectionDesc> clonedConns;
|
||||
synchronized(this) {
|
||||
clonedConns = new ArrayList<>(conns);
|
||||
}
|
||||
List<ConnectionDesc> expired = new ArrayList<>();
|
||||
|
||||
for (ConnectionDesc entry : clonedConns) {
|
||||
d("expire(): ", entry);
|
||||
if (entry.expire(threshold)) {
|
||||
expired.add(entry);
|
||||
td("expire(): Expired ", entry);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
conns.removeAll(expired);
|
||||
// Don't need to call notify() because we're
|
||||
// removing only idle connections. If there were
|
||||
// idle connections, then there should be no waiters.
|
||||
return conns.isEmpty(); // whether whole list has 'expired'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this instance of Connections has been removed from Pool.
|
||||
* This means that no one can get any pooled connections from this
|
||||
* Connections any longer. Expire all idle connections as of 'now'
|
||||
* and leave indicator so that any in-use connections will be closed upon
|
||||
* their return.
|
||||
*/
|
||||
synchronized void close() {
|
||||
expire(System.currentTimeMillis()); // Expire idle connections
|
||||
closed = true; // Close in-use connections when they are returned
|
||||
}
|
||||
|
||||
String getStats() {
|
||||
int idle = 0;
|
||||
int busy = 0;
|
||||
int expired = 0;
|
||||
long use = 0;
|
||||
int len;
|
||||
|
||||
synchronized (this) {
|
||||
len = conns.size();
|
||||
|
||||
ConnectionDesc entry;
|
||||
for (int i = 0; i < len; i++) {
|
||||
entry = conns.get(i);
|
||||
use += entry.getUseCount();
|
||||
switch (entry.getState()) {
|
||||
case ConnectionDesc.BUSY:
|
||||
++busy;
|
||||
break;
|
||||
case ConnectionDesc.IDLE:
|
||||
++idle;
|
||||
break;
|
||||
case ConnectionDesc.EXPIRED:
|
||||
++expired;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "size=" + len + "; use=" + use + "; busy=" + busy
|
||||
+ "; idle=" + idle + "; expired=" + expired;
|
||||
}
|
||||
|
||||
private void d(String msg, Object o1) {
|
||||
if (debug) {
|
||||
d(msg + o1);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, int i) {
|
||||
if (debug) {
|
||||
d(msg + i);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + "; size: " + conns.size());
|
||||
}
|
||||
}
|
||||
|
||||
private void td(String msg, Object o1, Object o2) {
|
||||
if (trace) { // redo test to avoid object creation
|
||||
td(msg + o1 + "[" + o2 + "]");
|
||||
}
|
||||
}
|
||||
private void td(String msg, Object o1) {
|
||||
if (trace) { // redo test to avoid object creation
|
||||
td(msg + o1);
|
||||
}
|
||||
}
|
||||
private void td(String msg) {
|
||||
if (trace) {
|
||||
System.err.println(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsRef.java
Normal file
58
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsRef.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, 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.ldap.pool;
|
||||
|
||||
/**
|
||||
* Is a reference to Connections that is stored in Pool.
|
||||
* This is an intermediate object that is outside of the circular
|
||||
* reference loop of
|
||||
* com.sun.jndi.ldap.Connection <-> com.sun.jndi.ldap.LdapClient
|
||||
* <-> com.sun.jndi.ldap.pool.Connections
|
||||
*
|
||||
* Because Connection is a daemon thread, it will keep LdapClient
|
||||
* alive until LdapClient closes Connection. This will in turn
|
||||
* keep Connections alive. So even when Connections is removed
|
||||
* from (the WeakHashMap of) Pool, it won't be finalized.
|
||||
* ConnectionsRef acts as Connections's finalizer.
|
||||
*
|
||||
* Without connection pooling, com.sun.jndi.ldap.LdapCtx's finalize()
|
||||
* closes LdapClient, which in turn closes Connection.
|
||||
* With connection pooling, ConnectionsRef's finalize() calls
|
||||
* Connections.close(), which in turn will close all idle connections
|
||||
* and mark Connections such that in-use connections will be closed
|
||||
* when they are returned to the pool.
|
||||
*/
|
||||
final class ConnectionsRef {
|
||||
final private Connections conns;
|
||||
|
||||
ConnectionsRef(Connections conns) {
|
||||
this.conns = conns;
|
||||
}
|
||||
|
||||
Connections getConnections() {
|
||||
return conns;
|
||||
}
|
||||
}
|
||||
71
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsWeakRef.java
Normal file
71
jdkSrc/jdk8/com/sun/jndi/ldap/pool/ConnectionsWeakRef.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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.ldap.pool;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
|
||||
/*
|
||||
* This class defines a WeakReference to the ConnectionRef (the referent).
|
||||
*
|
||||
* The ConnectionRef enables to break the reference
|
||||
* cycle between Connection, LdapClient, Connections and ConnectionDesc,
|
||||
* shown in the figure below.
|
||||
*
|
||||
* -------> Connections -----> ConnectionDesc
|
||||
* | ^ |
|
||||
* | | |
|
||||
* | | |
|
||||
* ConnectionsRef LdapClient <------------
|
||||
* ^ | ^
|
||||
* : | |
|
||||
* : v |
|
||||
* ConnectionsWeakRef Connection
|
||||
*
|
||||
* The ConnectionsRef is for cleaning up the resources held by the
|
||||
* Connection thread by making them available to the GC. The pool
|
||||
* uses ConnectionRef to hold the pooled resources.
|
||||
*
|
||||
* This class in turn holds a WeakReference with a ReferenceQueue to the
|
||||
* ConnectionRef to track when the ConnectionRef becomes ready
|
||||
* for getting GC'ed. It extends from WeakReference in order to hold a
|
||||
* reference to Connections used for closing (which in turn terminates
|
||||
* the Connection thread) it by monitoring the ReferenceQueue.
|
||||
*/
|
||||
class ConnectionsWeakRef extends WeakReference<ConnectionsRef> {
|
||||
|
||||
private final Connections conns;
|
||||
|
||||
ConnectionsWeakRef (ConnectionsRef connsRef,
|
||||
ReferenceQueue<? super ConnectionsRef> queue) {
|
||||
super(connsRef, queue);
|
||||
this.conns = connsRef.getConnections();
|
||||
}
|
||||
|
||||
Connections getConnections() {
|
||||
return conns;
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Pool.java
Normal file
254
jdkSrc/jdk8/com/sun/jndi/ldap/pool/Pool.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* A map of pool ids to Connections.
|
||||
* Key is an object that uniquely identifies a PooledConnection request
|
||||
* (typically information needed to create the connection).
|
||||
* The definitions of the key's equals() and hashCode() methods are
|
||||
* vital to its unique identification in a Pool.
|
||||
*
|
||||
* Value is a ConnectionsRef, which is a reference to Connections,
|
||||
* a list of equivalent connections.
|
||||
*
|
||||
* Supports methods that
|
||||
* - retrieves (or creates as necessary) a connection from the pool
|
||||
* - removes expired connections from the pool
|
||||
*
|
||||
* Connections cleanup:
|
||||
* A WeakHashMap is used for mapping the pool ids and Connections.
|
||||
* A SoftReference from the value to the key is kept to hold the map
|
||||
* entry as long as possible. This allows the GC to remove Connections
|
||||
* from the Pool under situations of VM running out of resources.
|
||||
* To take an appropriate action of 'closing the connections' before the GC
|
||||
* reclaims the ConnectionsRef objects, the ConnectionsRef objects are made
|
||||
* weakly reachable through a list of weak references registered with
|
||||
* a reference queue.
|
||||
* Upon an entry gets removed from the WeakHashMap, the ConnectionsRef (value
|
||||
* in the map) object is weakly reachable. When another sweep of
|
||||
* clearing the weak references is made by the GC it puts the corresponding
|
||||
* ConnectionsWeakRef object into the reference queue.
|
||||
* The reference queue is monitored lazily for reclaimable Connections
|
||||
* whenever a pooled connection is requested or a call to remove the expired
|
||||
* connections is made. The monitoring is done regularly when idle connection
|
||||
* timeout is set as the PoolCleaner removes expired connections periodically.
|
||||
* As determined by the experiements, cleanup of resources using the
|
||||
* ReferenceQueue mechanism is reliable and has immidiate effect than the
|
||||
* finalizer approach.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final public class Pool {
|
||||
|
||||
static final boolean debug = com.sun.jndi.ldap.LdapPoolManager.debug;
|
||||
|
||||
/*
|
||||
* Used for connections cleanup
|
||||
*/
|
||||
private static final ReferenceQueue<ConnectionsRef> queue =
|
||||
new ReferenceQueue<>();
|
||||
private static final Collection<Reference<ConnectionsRef>> weakRefs =
|
||||
Collections.synchronizedList(new LinkedList<Reference<ConnectionsRef>>());
|
||||
|
||||
final private int maxSize; // max num of identical conn per pool
|
||||
final private int prefSize; // preferred num of identical conn per pool
|
||||
final private int initSize; // initial number of identical conn to create
|
||||
final private Map<Object, ConnectionsRef> map;
|
||||
|
||||
public Pool(int initSize, int prefSize, int maxSize) {
|
||||
map = new WeakHashMap<>();
|
||||
this.prefSize = prefSize;
|
||||
this.maxSize = maxSize;
|
||||
this.initSize = initSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pooled connection for id. The pooled connection might be
|
||||
* newly created, as governed by the maxSize and prefSize settings.
|
||||
* If a pooled connection is unavailable and cannot be created due
|
||||
* to the maxSize constraint, this call blocks until the constraint
|
||||
* is removed or until 'timeout' ms has elapsed.
|
||||
*
|
||||
* @param id identity of the connection to get
|
||||
* @param timeout the number of milliseconds to wait before giving up
|
||||
* @param factory the factory to use for creating the connection if
|
||||
* creation is necessary
|
||||
* @return a pooled connection
|
||||
* @throws NamingException the connection could not be created due to
|
||||
* an error.
|
||||
*/
|
||||
public PooledConnection getPooledConnection(Object id, long timeout,
|
||||
PooledConnectionFactory factory) throws NamingException {
|
||||
|
||||
d("get(): ", id);
|
||||
if (debug) {
|
||||
synchronized (map) {
|
||||
d("size: ", map.size());
|
||||
}
|
||||
}
|
||||
|
||||
expungeStaleConnections();
|
||||
|
||||
Connections conns;
|
||||
synchronized (map) {
|
||||
conns = getConnections(id);
|
||||
if (conns == null) {
|
||||
d("get(): creating new connections list for ", id);
|
||||
|
||||
// No connections for this id so create a new list
|
||||
conns = new Connections(id, initSize, prefSize, maxSize,
|
||||
factory);
|
||||
ConnectionsRef connsRef = new ConnectionsRef(conns);
|
||||
map.put(id, connsRef);
|
||||
|
||||
// Create a weak reference to ConnectionsRef
|
||||
Reference<ConnectionsRef> weakRef =
|
||||
new ConnectionsWeakRef(connsRef, queue);
|
||||
|
||||
// Keep the weak reference through the element of a linked list
|
||||
weakRefs.add(weakRef);
|
||||
}
|
||||
d("get(): size after: ", map.size());
|
||||
}
|
||||
|
||||
return conns.get(timeout, factory); // get one connection from list
|
||||
}
|
||||
|
||||
private Connections getConnections(Object id) {
|
||||
ConnectionsRef ref = map.get(id);
|
||||
return (ref != null) ? ref.getConnections() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the connections in this Pool and expires ones that
|
||||
* have been idle before 'threshold'. An expired connection is closed
|
||||
* and then removed from the pool (removePooledConnection() will eventually
|
||||
* be called, and the list of pools itself removed if it becomes empty).
|
||||
*
|
||||
* @param threshold connections idle before 'threshold' should be closed
|
||||
* and removed.
|
||||
*/
|
||||
public void expire(long threshold) {
|
||||
Collection<ConnectionsRef> copy;
|
||||
synchronized (map) {
|
||||
copy = new ArrayList<>(map.values());
|
||||
}
|
||||
|
||||
ArrayList<ConnectionsRef> removed = new ArrayList<>();
|
||||
Connections conns;
|
||||
for (ConnectionsRef ref : copy) {
|
||||
conns = ref.getConnections();
|
||||
if (conns.expire(threshold)) {
|
||||
d("expire(): removing ", conns);
|
||||
removed.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (map) {
|
||||
map.values().removeAll(removed);
|
||||
}
|
||||
|
||||
expungeStaleConnections();
|
||||
}
|
||||
|
||||
/*
|
||||
* Closes the connections contained in the ConnectionsRef object that
|
||||
* is going to be reclaimed by the GC. Called by getPooledConnection()
|
||||
* and expire() methods of this class.
|
||||
*/
|
||||
private static void expungeStaleConnections() {
|
||||
ConnectionsWeakRef releaseRef = null;
|
||||
while ((releaseRef = (ConnectionsWeakRef) queue.poll())
|
||||
!= null) {
|
||||
Connections conns = releaseRef.getConnections();
|
||||
|
||||
if (debug) {
|
||||
System.err.println(
|
||||
"weak reference cleanup: Closing Connections:" + conns);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
conns.close();
|
||||
weakRefs.remove(releaseRef);
|
||||
releaseRef.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void showStats(PrintStream out) {
|
||||
Object id;
|
||||
Connections conns;
|
||||
|
||||
out.println("===== Pool start ======================");
|
||||
out.println("maximum pool size: " + maxSize);
|
||||
out.println("preferred pool size: " + prefSize);
|
||||
out.println("initial pool size: " + initSize);
|
||||
|
||||
synchronized (map) {
|
||||
out.println("current pool size: " + map.size());
|
||||
|
||||
for (Map.Entry<Object, ConnectionsRef> entry : map.entrySet()) {
|
||||
id = entry.getKey();
|
||||
conns = entry.getValue().getConnections();
|
||||
out.println(" " + id + ":" + conns.getStats());
|
||||
}
|
||||
}
|
||||
|
||||
out.println("====== Pool end =====================");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
synchronized (map) {
|
||||
return super.toString() + " " + map.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, int i) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + i);
|
||||
}
|
||||
}
|
||||
|
||||
private void d(String msg, Object obj) {
|
||||
if (debug) {
|
||||
System.err.println(this + "." + msg + obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCallback.java
Normal file
63
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCallback.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a callback used to release or remove a PooledConnection back
|
||||
* into the pool.
|
||||
*
|
||||
* A pooled connection typically has a close method that its clients
|
||||
* use to indicate that they no longer need the connection. This close
|
||||
* method should use the methods defined in this interface to
|
||||
* interact with the connection pool to return the connection
|
||||
* to the pool.
|
||||
*
|
||||
* The methods in this interface are typically invoked by a PooledConnection.
|
||||
* The methods in this interface are typically implemented by the connection
|
||||
* pool manager.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PoolCallback {
|
||||
/**
|
||||
* Releases a useable connection back to the pool.
|
||||
*
|
||||
* @param conn The connection to release.
|
||||
* @return true if the connection released; false if the connection
|
||||
* is no longer in the pool.
|
||||
*/
|
||||
public abstract boolean releasePooledConnection(PooledConnection conn);
|
||||
|
||||
/**
|
||||
* Removes a connection from the pool. The connection should not be reused.
|
||||
* The physical connection should have already been closed.
|
||||
*
|
||||
* @param conn The connection to return.
|
||||
* @return true if the connection was removed; false if the connection
|
||||
* is no longer in the pool prior to removal.
|
||||
*/
|
||||
public abstract boolean removePooledConnection(PooledConnection conn);
|
||||
}
|
||||
68
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCleaner.java
Normal file
68
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PoolCleaner.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
/**
|
||||
* Thread that wakes up periodically and closes expired, unused connections.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final public class PoolCleaner implements Runnable {
|
||||
final private Pool[] pools;
|
||||
final private long period;
|
||||
|
||||
/**
|
||||
* @param period ms to wait between cleaning
|
||||
* @param pools non-null array of Pools to clean
|
||||
*/
|
||||
public PoolCleaner(long period, Pool[] pools) {
|
||||
super();
|
||||
this.period = period;
|
||||
this.pools = pools.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long threshold;
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
// Wait for duration of period ms
|
||||
try {
|
||||
wait(period);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
|
||||
// Connections idle since threshold have expired
|
||||
threshold = System.currentTimeMillis() - period;
|
||||
for (int i = 0; i < pools.length; i++) {
|
||||
if (pools[i] != null) {
|
||||
pools[i].expire(threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PooledConnection.java
Normal file
53
jdkSrc/jdk8/com/sun/jndi/ldap/pool/PooledConnection.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
|
||||
/**
|
||||
* Represents a connection that is managed in a pool. The connection
|
||||
* may be reused by multiple clients.
|
||||
*
|
||||
* A pooled connection typically has a close method that its clients
|
||||
* use to indicate that they no longer need the connection. This close
|
||||
* method would interact with the connection pool to return the connection
|
||||
* to the pool (see PoolCallback).
|
||||
*<p>
|
||||
* The pooled connection also needs to provide a close method that the
|
||||
* connection pool can use to physically close the connection.
|
||||
* The pool might need to physically close the connection as determined
|
||||
* by the pool's policy (for example, to manage the pool size or idle
|
||||
* connections). This second close method should *not* use PoolCallback
|
||||
* methods. It should only do what is required to close the physical
|
||||
* connection.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PooledConnection {
|
||||
|
||||
/**
|
||||
* Closes the physical connection.
|
||||
*/
|
||||
public abstract void closeConnection();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 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.ldap.pool;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* Represents a factory that creates PooledConnection.
|
||||
*
|
||||
* The user of the connection pool should provide an implementation of this
|
||||
* interface and pass it to the Pool.getPooledConnection() method.
|
||||
* The implementation of the factory should contain all the information
|
||||
* necessary to create a PooledConnection.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public interface PooledConnectionFactory {
|
||||
/**
|
||||
* Creates a pooled connection.
|
||||
* @param pcb callback responsible for removing and releasing the pooled
|
||||
* connection from the pool.
|
||||
*/
|
||||
public abstract PooledConnection createPooledConnection(PoolCallback pcb)
|
||||
throws NamingException;
|
||||
};
|
||||
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/DefaultCallbackHandler.java
Normal file
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/DefaultCallbackHandler.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.ldap.sasl;
|
||||
|
||||
import javax.security.auth.callback.*;
|
||||
import javax.security.sasl.RealmCallback;
|
||||
import javax.security.sasl.RealmChoiceCallback;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DefaultCallbackHandler for satisfying NameCallback and
|
||||
* PasswordCallback for an LDAP client.
|
||||
* NameCallback is used for getting the authentication ID and is
|
||||
* gotten from the java.naming.security.principal property.
|
||||
* PasswordCallback is gotten from the java.naming.security.credentials
|
||||
* property and must be of type String, char[] or byte[].
|
||||
* If byte[], it is assumed to have UTF-8 encoding.
|
||||
*
|
||||
* If the caller of getPassword() will be using the password as
|
||||
* a byte array, then it should encode the char[] array returned by
|
||||
* getPassword() into a byte[] using UTF-8.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
final class DefaultCallbackHandler implements CallbackHandler {
|
||||
private char[] passwd;
|
||||
private String authenticationID;
|
||||
private String authRealm;
|
||||
|
||||
DefaultCallbackHandler(String principal, Object cred, String realm)
|
||||
throws IOException {
|
||||
authenticationID = principal;
|
||||
authRealm = realm;
|
||||
if (cred instanceof String) {
|
||||
passwd = ((String)cred).toCharArray();
|
||||
} else if (cred instanceof char[]) {
|
||||
passwd = ((char[])cred).clone();
|
||||
} else if (cred != null) {
|
||||
// assume UTF-8 encoding
|
||||
String orig = new String((byte[])cred, "UTF8");
|
||||
passwd = orig.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks)
|
||||
throws IOException, UnsupportedCallbackException {
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
((NameCallback)callbacks[i]).setName(authenticationID);
|
||||
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
((PasswordCallback)callbacks[i]).setPassword(passwd);
|
||||
|
||||
} else if (callbacks[i] instanceof RealmChoiceCallback) {
|
||||
/* Deals with a choice of realms */
|
||||
String[] choices =
|
||||
((RealmChoiceCallback)callbacks[i]).getChoices();
|
||||
int selected = 0;
|
||||
|
||||
if (authRealm != null && authRealm.length() > 0) {
|
||||
selected = -1; // no realm chosen
|
||||
for (int j = 0; j < choices.length; j++) {
|
||||
if (choices[j].equals(authRealm)) {
|
||||
selected = j;
|
||||
}
|
||||
}
|
||||
if (selected == -1) {
|
||||
StringBuffer allChoices = new StringBuffer();
|
||||
for (int j = 0; j < choices.length; j++) {
|
||||
allChoices.append(choices[j] + ",");
|
||||
}
|
||||
throw new IOException("Cannot match " +
|
||||
"'java.naming.security.sasl.realm' property value, '" +
|
||||
authRealm + "' with choices " + allChoices +
|
||||
"in RealmChoiceCallback");
|
||||
}
|
||||
}
|
||||
|
||||
((RealmChoiceCallback)callbacks[i]).setSelectedIndex(selected);
|
||||
|
||||
} else if (callbacks[i] instanceof RealmCallback) {
|
||||
/* 1 or 0 realms specified in challenge */
|
||||
RealmCallback rcb = (RealmCallback) callbacks[i];
|
||||
if (authRealm != null) {
|
||||
rcb.setText(authRealm); // Use what user supplied
|
||||
} else {
|
||||
String defaultRealm = rcb.getDefaultText();
|
||||
if (defaultRealm != null) {
|
||||
rcb.setText(defaultRealm); // Use what server supplied
|
||||
} else {
|
||||
rcb.setText(""); // Specify no realm
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callbacks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clearPassword() {
|
||||
if (passwd != null) {
|
||||
for (int i = 0; i < passwd.length; i++) {
|
||||
passwd[i] = '\0';
|
||||
}
|
||||
passwd = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
clearPassword();
|
||||
}
|
||||
}
|
||||
201
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/LdapSasl.java
Normal file
201
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/LdapSasl.java
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.ldap.sasl;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import javax.naming.ldap.Control;
|
||||
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.sasl.*;
|
||||
import com.sun.jndi.ldap.Connection;
|
||||
import com.sun.jndi.ldap.LdapClient;
|
||||
import com.sun.jndi.ldap.LdapResult;
|
||||
|
||||
/**
|
||||
* Handles SASL support.
|
||||
*
|
||||
* @author Vincent Ryan
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
|
||||
final public class LdapSasl {
|
||||
// SASL stuff
|
||||
private static final String SASL_CALLBACK = "java.naming.security.sasl.callback";
|
||||
private static final String SASL_AUTHZ_ID =
|
||||
"java.naming.security.sasl.authorizationId";
|
||||
private static final String SASL_REALM =
|
||||
"java.naming.security.sasl.realm";
|
||||
|
||||
private static final int LDAP_SUCCESS = 0;
|
||||
private static final int LDAP_SASL_BIND_IN_PROGRESS = 14; // LDAPv3
|
||||
|
||||
private LdapSasl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs SASL bind.
|
||||
* Creates a SaslClient by using a default CallbackHandler
|
||||
* that uses the Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS
|
||||
* properties to satisfy the callbacks, and by using the
|
||||
* SASL_AUTHZ_ID property as the authorization id. If the SASL_AUTHZ_ID
|
||||
* property has not been set, Context.SECURITY_PRINCIPAL is used.
|
||||
* If SASL_CALLBACK has been set, use that instead of the default
|
||||
* CallbackHandler.
|
||||
*<p>
|
||||
* If bind is successful and the selected SASL mechanism has a security
|
||||
* layer, set inStream and outStream to be filter streams that use
|
||||
* the security layer. These will be used for subsequent communication
|
||||
* with the server.
|
||||
*<p>
|
||||
* @param conn The non-null connection to use for sending an LDAP BIND
|
||||
* @param server Non-null string name of host to connect to
|
||||
* @param dn Non-null DN to bind as; also used as authentication ID
|
||||
* @param pw Possibly null password; can be byte[], char[] or String
|
||||
* @param authMech A non-null space-separated list of SASL authentication
|
||||
* mechanisms.
|
||||
* @param env The possibly null environment of the context, possibly containing
|
||||
* properties for used by SASL mechanisms
|
||||
* @param bindCtls The possibly null controls to accompany the bind
|
||||
* @return LdapResult containing status of the bind
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static LdapResult saslBind(LdapClient clnt, Connection conn,
|
||||
String server, String dn, Object pw,
|
||||
String authMech, Hashtable<?,?> env, Control[] bindCtls)
|
||||
throws IOException, NamingException {
|
||||
|
||||
SaslClient saslClnt = null;
|
||||
boolean cleanupHandler = false;
|
||||
|
||||
// Use supplied callback handler or create default
|
||||
CallbackHandler cbh =
|
||||
(env != null) ? (CallbackHandler)env.get(SASL_CALLBACK) : null;
|
||||
if (cbh == null) {
|
||||
cbh = new DefaultCallbackHandler(dn, pw, (String)env.get(SASL_REALM));
|
||||
cleanupHandler = true;
|
||||
}
|
||||
|
||||
// Prepare parameters for creating SASL client
|
||||
String authzId = (env != null) ? (String)env.get(SASL_AUTHZ_ID) : null;
|
||||
String[] mechs = getSaslMechanismNames(authMech);
|
||||
|
||||
try {
|
||||
// Create SASL client to use using SASL package
|
||||
saslClnt = Sasl.createSaslClient(
|
||||
mechs, authzId, "ldap", server, (Hashtable<String, ?>)env, cbh);
|
||||
|
||||
if (saslClnt == null) {
|
||||
throw new AuthenticationNotSupportedException(authMech);
|
||||
}
|
||||
|
||||
LdapResult res;
|
||||
String mechName = saslClnt.getMechanismName();
|
||||
byte[] response = saslClnt.hasInitialResponse() ?
|
||||
saslClnt.evaluateChallenge(NO_BYTES) : null;
|
||||
|
||||
res = clnt.ldapBind(null, response, bindCtls, mechName, true);
|
||||
|
||||
while (!saslClnt.isComplete() &&
|
||||
(res.status == LDAP_SASL_BIND_IN_PROGRESS ||
|
||||
res.status == LDAP_SUCCESS)) {
|
||||
|
||||
response = saslClnt.evaluateChallenge(
|
||||
res.serverCreds != null? res.serverCreds : NO_BYTES);
|
||||
if (res.status == LDAP_SUCCESS) {
|
||||
if (response != null) {
|
||||
throw new AuthenticationException(
|
||||
"SASL client generated response after success");
|
||||
}
|
||||
break;
|
||||
}
|
||||
res = clnt.ldapBind(null, response, bindCtls, mechName, true);
|
||||
}
|
||||
|
||||
if (res.status == LDAP_SUCCESS) {
|
||||
if (!saslClnt.isComplete()) {
|
||||
throw new AuthenticationException(
|
||||
"SASL authentication not complete despite server claims");
|
||||
}
|
||||
|
||||
String qop = (String) saslClnt.getNegotiatedProperty(Sasl.QOP);
|
||||
|
||||
// If negotiated integrity or privacy,
|
||||
if (qop != null && (qop.equalsIgnoreCase("auth-int")
|
||||
|| qop.equalsIgnoreCase("auth-conf"))) {
|
||||
|
||||
InputStream newIn = new SaslInputStream(saslClnt,
|
||||
conn.inStream);
|
||||
OutputStream newOut = new SaslOutputStream(saslClnt,
|
||||
conn.outStream);
|
||||
|
||||
conn.replaceStreams(newIn, newOut);
|
||||
} else {
|
||||
saslClnt.dispose();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} catch (SaslException e) {
|
||||
NamingException ne = new AuthenticationException(
|
||||
authMech);
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
} finally {
|
||||
if (cleanupHandler) {
|
||||
((DefaultCallbackHandler)cbh).clearPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of SASL mechanisms given a string of space
|
||||
* separated SASL mechanism names.
|
||||
* @param The non-null string containing the mechanism names
|
||||
* @return A non-null array of String; each element of the array
|
||||
* contains a single mechanism name.
|
||||
*/
|
||||
private static String[] getSaslMechanismNames(String str) {
|
||||
StringTokenizer parser = new StringTokenizer(str);
|
||||
Vector<String> mechs = new Vector<>(10);
|
||||
while (parser.hasMoreTokens()) {
|
||||
mechs.addElement(parser.nextToken());
|
||||
}
|
||||
String[] mechNames = new String[mechs.size()];
|
||||
for (int i = 0; i < mechs.size(); i++) {
|
||||
mechNames[i] = mechs.elementAt(i);
|
||||
}
|
||||
return mechNames;
|
||||
}
|
||||
|
||||
private static final byte[] NO_BYTES = new byte[0];
|
||||
}
|
||||
218
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslInputStream.java
Normal file
218
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslInputStream.java
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, 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.ldap.sasl;
|
||||
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* This class is used by clients of Java SASL that need to create an input stream
|
||||
* that uses SaslClient's unwrap() method to decode the SASL buffers
|
||||
* sent by the SASL server.
|
||||
*
|
||||
* Extend from InputStream instead of FilterInputStream because
|
||||
* we need to override less methods in InputStream. That is, the
|
||||
* behavior of the default implementations in InputStream matches
|
||||
* more closely with the behavior we want in SaslInputStream.
|
||||
*
|
||||
* @author Rosanna Lee
|
||||
*/
|
||||
public class SaslInputStream extends InputStream {
|
||||
private static final boolean debug = false;
|
||||
|
||||
private byte[] saslBuffer; // buffer for storing raw bytes
|
||||
private byte[] lenBuf = new byte[4]; // buffer for storing length
|
||||
|
||||
private byte[] buf = new byte[0]; // buffer for storing processed bytes
|
||||
// Initialized to empty buffer
|
||||
private int bufPos = 0; // read position in buf
|
||||
private InputStream in; // underlying input stream
|
||||
private SaslClient sc;
|
||||
private int recvMaxBufSize = 65536;
|
||||
|
||||
SaslInputStream(SaslClient sc, InputStream in) throws SaslException {
|
||||
super();
|
||||
this.in = in;
|
||||
this.sc = sc;
|
||||
|
||||
String str = (String) sc.getNegotiatedProperty(Sasl.MAX_BUFFER);
|
||||
if (str != null) {
|
||||
try {
|
||||
recvMaxBufSize = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SaslException(Sasl.MAX_BUFFER +
|
||||
" property must be numeric string: " + str);
|
||||
}
|
||||
}
|
||||
saslBuffer = new byte[recvMaxBufSize];
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] inBuf = new byte[1];
|
||||
int count = read(inBuf, 0, 1);
|
||||
if (count > 0) {
|
||||
return inBuf[0];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte[] inBuf, int start, int count) throws IOException {
|
||||
|
||||
if (bufPos >= buf.length) {
|
||||
int actual = fill(); // read and unwrap next SASL buffer
|
||||
while (actual == 0) { // ignore zero length content
|
||||
actual = fill();
|
||||
}
|
||||
if (actual == -1) {
|
||||
return -1; // EOF
|
||||
}
|
||||
}
|
||||
|
||||
int avail = buf.length - bufPos;
|
||||
if (count > avail) {
|
||||
// Requesting more that we have stored
|
||||
// Return all that we have; next invocation of read() will
|
||||
// trigger fill()
|
||||
System.arraycopy(buf, bufPos, inBuf, start, avail);
|
||||
bufPos = buf.length;
|
||||
return avail;
|
||||
} else {
|
||||
// Requesting less than we have stored
|
||||
// Return all that was requested
|
||||
System.arraycopy(buf, bufPos, inBuf, start, count);
|
||||
bufPos += count;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the buf with more data by reading a SASL buffer, unwrapping it,
|
||||
* and leaving the bytes in buf for read() to return.
|
||||
* @return The number of unwrapped bytes available
|
||||
*/
|
||||
private int fill() throws IOException {
|
||||
// Read in length of buffer
|
||||
int actual = readFully(lenBuf, 4);
|
||||
if (actual != 4) {
|
||||
return -1;
|
||||
}
|
||||
int len = networkByteOrderToInt(lenBuf, 0, 4);
|
||||
|
||||
if (len > recvMaxBufSize) {
|
||||
throw new IOException(
|
||||
len + "exceeds the negotiated receive buffer size limit:" +
|
||||
recvMaxBufSize);
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.err.println("reading " + len + " bytes from network");
|
||||
}
|
||||
|
||||
// Read SASL buffer
|
||||
actual = readFully(saslBuffer, len);
|
||||
if (actual != len) {
|
||||
throw new EOFException("Expecting to read " + len +
|
||||
" bytes but got " + actual + " bytes before EOF");
|
||||
}
|
||||
|
||||
// Unwrap
|
||||
buf = sc.unwrap(saslBuffer, 0, len);
|
||||
|
||||
bufPos = 0;
|
||||
|
||||
return buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read requested number of bytes before returning.
|
||||
* @return The number of bytes actually read; -1 if none read
|
||||
*/
|
||||
private int readFully(byte[] inBuf, int total) throws IOException {
|
||||
int count, pos = 0;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("readFully " + total + " from " + in);
|
||||
}
|
||||
|
||||
while (total > 0) {
|
||||
count = in.read(inBuf, pos, total);
|
||||
|
||||
if (debug) {
|
||||
System.err.println("readFully read " + count);
|
||||
}
|
||||
|
||||
if (count == -1 ) {
|
||||
return (pos == 0? -1 : pos);
|
||||
}
|
||||
pos += count;
|
||||
total -= count;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return buf.length - bufPos;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
SaslException save = null;
|
||||
try {
|
||||
sc.dispose(); // Dispose of SaslClient's state
|
||||
} catch (SaslException e) {
|
||||
// Save exception for throwing after closing 'in'
|
||||
save = e;
|
||||
}
|
||||
|
||||
in.close(); // Close underlying input stream
|
||||
|
||||
if (save != null) {
|
||||
throw save;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer represented by 4 bytes in network byte order.
|
||||
*/
|
||||
// Copied from com.sun.security.sasl.util.SaslImpl.
|
||||
private static int networkByteOrderToInt(byte[] buf, int start, int count) {
|
||||
if (count > 4) {
|
||||
throw new IllegalArgumentException("Cannot handle more than 4 bytes");
|
||||
}
|
||||
|
||||
int answer = 0;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
answer <<= 8;
|
||||
answer |= ((int)buf[start+i] & 0xff);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslOutputStream.java
Normal file
135
jdkSrc/jdk8/com/sun/jndi/ldap/sasl/SaslOutputStream.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, 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.ldap.sasl;
|
||||
|
||||
import javax.security.sasl.Sasl;
|
||||
import javax.security.sasl.SaslClient;
|
||||
import javax.security.sasl.SaslException;
|
||||
import java.io.IOException;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class SaslOutputStream extends FilterOutputStream {
|
||||
private static final boolean debug = false;
|
||||
|
||||
private byte[] lenBuf = new byte[4]; // buffer for storing length
|
||||
private int rawSendSize = 65536;
|
||||
private SaslClient sc;
|
||||
|
||||
SaslOutputStream(SaslClient sc, OutputStream out) throws SaslException {
|
||||
super(out);
|
||||
this.sc = sc;
|
||||
|
||||
if (debug) {
|
||||
System.err.println("SaslOutputStream: " + out);
|
||||
}
|
||||
|
||||
String str = (String) sc.getNegotiatedProperty(Sasl.RAW_SEND_SIZE);
|
||||
if (str != null) {
|
||||
try {
|
||||
rawSendSize = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new SaslException(Sasl.RAW_SEND_SIZE +
|
||||
" property must be numeric string: " + str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override this method to call write(byte[], int, int) counterpart
|
||||
// super.write(int) simply calls out.write(int)
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
byte[] buffer = new byte[1];
|
||||
buffer[0] = (byte)b;
|
||||
write(buffer, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to "wrap" the outgoing buffer before
|
||||
* writing it to the underlying output stream.
|
||||
*/
|
||||
public void write(byte[] buffer, int offset, int total) throws IOException {
|
||||
int count;
|
||||
byte[] wrappedToken, saslBuffer;
|
||||
|
||||
// "Packetize" buffer to be within rawSendSize
|
||||
if (debug) {
|
||||
System.err.println("Total size: " + total);
|
||||
}
|
||||
|
||||
for (int i = 0; i < total; i += rawSendSize) {
|
||||
|
||||
// Calculate length of current "packet"
|
||||
count = (total - i) < rawSendSize ? (total - i) : rawSendSize;
|
||||
|
||||
// Generate wrapped token
|
||||
wrappedToken = sc.wrap(buffer, offset+i, count);
|
||||
|
||||
// Write out length
|
||||
intToNetworkByteOrder(wrappedToken.length, lenBuf, 0, 4);
|
||||
|
||||
if (debug) {
|
||||
System.err.println("sending size: " + wrappedToken.length);
|
||||
}
|
||||
out.write(lenBuf, 0, 4);
|
||||
|
||||
// Write out wrapped token
|
||||
out.write(wrappedToken, 0, wrappedToken.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
SaslException save = null;
|
||||
try {
|
||||
sc.dispose(); // Dispose of SaslClient's state
|
||||
} catch (SaslException e) {
|
||||
// Save exception for throwing after closing 'in'
|
||||
save = e;
|
||||
}
|
||||
super.close(); // Close underlying output stream
|
||||
|
||||
if (save != null) {
|
||||
throw save;
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from com.sun.security.sasl.util.SaslImpl
|
||||
/**
|
||||
* Encodes an integer into 4 bytes in network byte order in the buffer
|
||||
* supplied.
|
||||
*/
|
||||
private static void intToNetworkByteOrder(int num, byte[] buf, int start,
|
||||
int count) {
|
||||
if (count > 4) {
|
||||
throw new IllegalArgumentException("Cannot handle more than 4 bytes");
|
||||
}
|
||||
|
||||
for (int i = count-1; i >= 0; i--) {
|
||||
buf[start+i] = (byte)(num & 0xff);
|
||||
num >>>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
109
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProvider.java
Normal file
109
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProvider.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.ldap.spi;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Service-provider class for DNS lookups when performing LDAP operations.
|
||||
*
|
||||
* <p> An LDAP DNS provider is a concrete subclass of this class that
|
||||
* has a zero-argument constructor. LDAP DNS providers are located using the
|
||||
* ServiceLoader facility, as specified by
|
||||
* {@linkplain javax.naming.directory.InitialDirContext InitialDirectContext}.
|
||||
*
|
||||
* The
|
||||
* {@link java.util.ServiceLoader ServiceLoader} is used to create and register
|
||||
* implementations of {@code LdapDnsProvider}.
|
||||
*
|
||||
* <p> An LDAP DNS provider can be used in environments where the default
|
||||
* DNS resolution mechanism is not sufficient to accurately pinpoint the
|
||||
* correct LDAP servers needed to perform LDAP operations. For example, in an
|
||||
* environment containing a mix of {@code ldap} and {@code ldaps} servers
|
||||
* you may want the {@linkplain javax.naming.ldap.LdapContext LdapContext}
|
||||
* to query {@code ldaps} servers only.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public abstract class LdapDnsProvider {
|
||||
|
||||
// The {@code RuntimePermission("ldapDnsProvider")} is
|
||||
// necessary to subclass and instantiate the {@code LdapDnsProvider} class.
|
||||
private static final RuntimePermission DNSPROVIDER_PERMISSION =
|
||||
new RuntimePermission("ldapDnsProvider");
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code LdapDnsProvider}.
|
||||
*
|
||||
* @throws SecurityException if a security manager is present and its
|
||||
* {@code checkPermission} method doesn't allow
|
||||
* the {@code RuntimePermission("ldapDnsProvider")}.
|
||||
*/
|
||||
protected LdapDnsProvider() {
|
||||
this(checkPermission());
|
||||
}
|
||||
|
||||
private LdapDnsProvider(Void unused) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
private static Void checkPermission() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(DNSPROVIDER_PERMISSION);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the endpoints and domain name for the given {@link Context}
|
||||
* {@link Context#PROVIDER_URL provider URL} and environment. The resolved
|
||||
* endpoints and domain name are returned as an
|
||||
* {@link LdapDnsProviderResult}.
|
||||
*
|
||||
* <p> An endpoint is a {@code String} representation of an LDAP URL which
|
||||
* points to an LDAP server to be used for LDAP operations. The syntax of
|
||||
* an LDAP URL is defined by <a href="http://www.ietf.org/rfc/rfc2255.txt">
|
||||
* <i>RFC 2255: The LDAP URL Format</i></a>.
|
||||
*
|
||||
* @param url The {@link Context} {@link Context#PROVIDER_URL provider URL}
|
||||
* @param env The {@link Context} environment.
|
||||
*
|
||||
* @return an {@link LdapDnsProviderResult} or empty {@code Optional}
|
||||
* if the lookup fails.
|
||||
*
|
||||
* @throws NamingException if the {@code url} is not valid or an error
|
||||
* occurred while performing the lookup.
|
||||
* @throws NullPointerException if either {@code url} or {@code env} are
|
||||
* {@code null}.
|
||||
*/
|
||||
public abstract Optional<LdapDnsProviderResult> lookupEndpoints(
|
||||
String url, Map<?,?> env) throws NamingException;
|
||||
|
||||
}
|
||||
88
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProviderResult.java
Normal file
88
jdkSrc/jdk8/com/sun/jndi/ldap/spi/LdapDnsProviderResult.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.ldap.spi;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The result of a DNS lookup for an LDAP URL.
|
||||
*
|
||||
* <p> This class is used by an {@link LdapDnsProvider} to return the result
|
||||
* of a DNS lookup for a given LDAP URL. The result consists of a domain name
|
||||
* and its associated ldap server endpoints.
|
||||
*
|
||||
* <p> A {@code null} {@code domainName} is equivalent to and represented
|
||||
* by an empty string.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public final class LdapDnsProviderResult {
|
||||
|
||||
private final String domainName;
|
||||
private final List<String> endpoints;
|
||||
|
||||
/**
|
||||
* Construct an LdapDnsProviderResult consisting of a resolved domain name
|
||||
* and the ldap server endpoints that serve the domain.
|
||||
*
|
||||
* @param domainName the resolved domain name; can be null.
|
||||
* @param endpoints the possibly empty list of resolved ldap server
|
||||
* endpoints
|
||||
*
|
||||
* @throws NullPointerException if {@code endpoints} contains {@code null}
|
||||
* elements.
|
||||
* @throws ClassCastException if {@code endpoints} contains non-
|
||||
* {@code String} elements.
|
||||
*/
|
||||
public LdapDnsProviderResult(String domainName, List<String> endpoints) {
|
||||
this.domainName = (domainName == null) ? "" : domainName;
|
||||
this.endpoints = new ArrayList<>(endpoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the domain name resolved from the ldap URL. This method returns
|
||||
* the empty string if the {@code LdapDnsProviderResult} is created with a
|
||||
* null domain name.
|
||||
*
|
||||
* @return the resolved domain name
|
||||
*/
|
||||
public String getDomainName() {
|
||||
return domainName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the possibly empty list of individual server endpoints resolved
|
||||
* from the ldap URL.
|
||||
*
|
||||
* @return a possibly empty unmodifiable {@link List} containing the
|
||||
* resolved ldap server endpoints
|
||||
*/
|
||||
public List<String> getEndpoints() {
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
}
|
||||
61
jdkSrc/jdk8/com/sun/jndi/rmi/registry/ReferenceWrapper.java
Normal file
61
jdkSrc/jdk8/com/sun/jndi/rmi/registry/ReferenceWrapper.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2002, 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.rmi.registry;
|
||||
|
||||
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* The ReferenceWrapper class is a Remote wrapper for Reference
|
||||
* objects. It wraps around a Reference on the server, and makes the
|
||||
* Reference accessible to clients.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class ReferenceWrapper
|
||||
extends UnicastRemoteObject
|
||||
implements RemoteReference
|
||||
{
|
||||
protected Reference wrappee; // reference being wrapped
|
||||
|
||||
public ReferenceWrapper(Reference wrappee)
|
||||
throws NamingException, RemoteException
|
||||
{
|
||||
this.wrappee = wrappee;
|
||||
}
|
||||
|
||||
public Reference getReference() throws RemoteException {
|
||||
return wrappee;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 6078186197417641456L;
|
||||
}
|
||||
640
jdkSrc/jdk8/com/sun/jndi/rmi/registry/RegistryContext.java
Normal file
640
jdkSrc/jdk8/com/sun/jndi/rmi/registry/RegistryContext.java
Normal file
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* 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.rmi.registry;
|
||||
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.*;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.spi.NamingManager;
|
||||
|
||||
|
||||
/**
|
||||
* A RegistryContext is a context representing a remote RMI registry.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class RegistryContext implements Context, Referenceable {
|
||||
|
||||
private Hashtable<String, Object> environment;
|
||||
private Registry registry;
|
||||
private String host;
|
||||
private int port;
|
||||
private static final NameParser nameParser = new AtomicNameParser();
|
||||
private static final String SOCKET_FACTORY = "com.sun.jndi.rmi.factory.socket";
|
||||
/**
|
||||
* Determines whether classes may be loaded from an arbitrary URL code base.
|
||||
*/
|
||||
static final boolean trustURLCodebase;
|
||||
static {
|
||||
// System property to control whether classes may be loaded from an
|
||||
// arbitrary URL codebase
|
||||
PrivilegedAction<String> act = () -> System.getProperty(
|
||||
"com.sun.jndi.rmi.object.trustURLCodebase", "false");
|
||||
String trust = AccessController.doPrivileged(act);
|
||||
trustURLCodebase = "true".equalsIgnoreCase(trust);
|
||||
}
|
||||
|
||||
Reference reference = null; // ref used to create this context, if any
|
||||
|
||||
// Environment property that, if set, indicates that a security
|
||||
// manager should be installed (if none is already in place).
|
||||
public static final String SECURITY_MGR =
|
||||
"java.naming.rmi.security.manager";
|
||||
|
||||
/**
|
||||
* Returns a context for the registry at a given host and port.
|
||||
* If "host" is null, uses default host.
|
||||
* If "port" is non-positive, uses default port.
|
||||
* Cloning of "env" is handled by caller; see comments within
|
||||
* RegistryContextFactory.getObjectInstance(), for example.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public RegistryContext(String host, int port, Hashtable<?, ?> env)
|
||||
throws NamingException
|
||||
{
|
||||
environment = (env == null)
|
||||
? new Hashtable<String, Object>(5)
|
||||
: (Hashtable<String, Object>) env;
|
||||
if (environment.get(SECURITY_MGR) != null) {
|
||||
installSecurityMgr();
|
||||
}
|
||||
|
||||
// chop off '[' and ']' in an IPv6 literal address
|
||||
if ((host != null) && (host.charAt(0) == '[')) {
|
||||
host = host.substring(1, host.length() - 1);
|
||||
}
|
||||
|
||||
RMIClientSocketFactory socketFactory =
|
||||
(RMIClientSocketFactory) environment.get(SOCKET_FACTORY);
|
||||
registry = getRegistry(host, port, socketFactory);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of a registry context. The context's private state
|
||||
* is independent of the original's (so closing one context, for example,
|
||||
* won't close the other).
|
||||
*/
|
||||
// %%% Alternatively, this could be done with a clone() method.
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
RegistryContext(RegistryContext ctx) {
|
||||
environment = (Hashtable<String, Object>)ctx.environment.clone();
|
||||
registry = ctx.registry;
|
||||
host = ctx.host;
|
||||
port = ctx.port;
|
||||
reference = ctx.reference;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
public Object lookup(Name name) throws NamingException {
|
||||
if (name.isEmpty()) {
|
||||
return (new RegistryContext(this));
|
||||
}
|
||||
Remote obj;
|
||||
try {
|
||||
obj = registry.lookup(name.get(0));
|
||||
} catch (NotBoundException e) {
|
||||
throw (new NameNotFoundException(name.get(0)));
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
return (decodeObject(obj, name.getPrefix(1)));
|
||||
}
|
||||
|
||||
public Object lookup(String name) throws NamingException {
|
||||
return lookup(new CompositeName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the object to be bound is both Remote and Referenceable, binds the
|
||||
* object itself, not its Reference.
|
||||
*/
|
||||
public void bind(Name name, Object obj) throws NamingException {
|
||||
if (name.isEmpty()) {
|
||||
throw (new InvalidNameException(
|
||||
"RegistryContext: Cannot bind empty name"));
|
||||
}
|
||||
try {
|
||||
registry.bind(name.get(0), encodeObject(obj, name.getPrefix(1)));
|
||||
} catch (AlreadyBoundException e) {
|
||||
NamingException ne = new NameAlreadyBoundException(name.get(0));
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj) throws NamingException {
|
||||
bind(new CompositeName(name), obj);
|
||||
}
|
||||
|
||||
public void rebind(Name name, Object obj) throws NamingException {
|
||||
if (name.isEmpty()) {
|
||||
throw (new InvalidNameException(
|
||||
"RegistryContext: Cannot rebind empty name"));
|
||||
}
|
||||
try {
|
||||
registry.rebind(name.get(0), encodeObject(obj, name.getPrefix(1)));
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void rebind(String name, Object obj) throws NamingException {
|
||||
rebind(new CompositeName(name), obj);
|
||||
}
|
||||
|
||||
public void unbind(Name name) throws NamingException {
|
||||
if (name.isEmpty()) {
|
||||
throw (new InvalidNameException(
|
||||
"RegistryContext: Cannot unbind empty name"));
|
||||
}
|
||||
try {
|
||||
registry.unbind(name.get(0));
|
||||
} catch (NotBoundException e) {
|
||||
// method is idempotent
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void unbind(String name) throws NamingException {
|
||||
unbind(new CompositeName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename is implemented by this sequence of operations:
|
||||
* lookup, bind, unbind. The sequence is not performed atomically.
|
||||
*/
|
||||
public void rename(Name oldName, Name newName) throws NamingException {
|
||||
bind(newName, lookup(oldName));
|
||||
unbind(oldName);
|
||||
}
|
||||
|
||||
public void rename(String name, String newName) throws NamingException {
|
||||
rename(new CompositeName(name), new CompositeName(newName));
|
||||
}
|
||||
|
||||
public NamingEnumeration<NameClassPair> list(Name name) throws
|
||||
NamingException {
|
||||
if (!name.isEmpty()) {
|
||||
throw (new InvalidNameException(
|
||||
"RegistryContext: can only list \"\""));
|
||||
}
|
||||
try {
|
||||
String[] names = registry.list();
|
||||
return (new NameClassPairEnumeration(names));
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<NameClassPair> list(String name) throws
|
||||
NamingException {
|
||||
return list(new CompositeName(name));
|
||||
}
|
||||
|
||||
public NamingEnumeration<Binding> listBindings(Name name)
|
||||
throws NamingException
|
||||
{
|
||||
if (!name.isEmpty()) {
|
||||
throw (new InvalidNameException(
|
||||
"RegistryContext: can only list \"\""));
|
||||
}
|
||||
try {
|
||||
String[] names = registry.list();
|
||||
return (new BindingEnumeration(this, names));
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public NamingEnumeration<Binding> listBindings(String name) throws
|
||||
NamingException {
|
||||
return listBindings(new CompositeName(name));
|
||||
}
|
||||
|
||||
public void destroySubcontext(Name name) throws NamingException {
|
||||
throw (new OperationNotSupportedException());
|
||||
}
|
||||
|
||||
public void destroySubcontext(String name) throws NamingException {
|
||||
throw (new OperationNotSupportedException());
|
||||
}
|
||||
|
||||
public Context createSubcontext(Name name) throws NamingException {
|
||||
throw (new OperationNotSupportedException());
|
||||
}
|
||||
|
||||
public Context createSubcontext(String name) throws NamingException {
|
||||
throw (new OperationNotSupportedException());
|
||||
}
|
||||
|
||||
public Object lookupLink(Name name) throws NamingException {
|
||||
return lookup(name);
|
||||
}
|
||||
|
||||
public Object lookupLink(String name) throws NamingException {
|
||||
return lookup(name);
|
||||
}
|
||||
|
||||
public NameParser getNameParser(Name name) throws NamingException {
|
||||
return nameParser;
|
||||
}
|
||||
|
||||
public NameParser getNameParser(String name) throws NamingException {
|
||||
return nameParser;
|
||||
}
|
||||
|
||||
public Name composeName(Name name, Name prefix) throws NamingException {
|
||||
Name result = (Name)prefix.clone();
|
||||
return result.addAll(name);
|
||||
}
|
||||
|
||||
public String composeName(String name, String prefix)
|
||||
throws NamingException
|
||||
{
|
||||
return composeName(new CompositeName(name),
|
||||
new CompositeName(prefix)).toString();
|
||||
}
|
||||
|
||||
public Object removeFromEnvironment(String propName)
|
||||
throws NamingException
|
||||
{
|
||||
return environment.remove(propName);
|
||||
}
|
||||
|
||||
public Object addToEnvironment(String propName, Object propVal)
|
||||
throws NamingException
|
||||
{
|
||||
if (propName.equals(SECURITY_MGR)) {
|
||||
installSecurityMgr();
|
||||
}
|
||||
return environment.put(propName, propVal);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // clone()
|
||||
public Hashtable<String, Object> getEnvironment() throws NamingException {
|
||||
return (Hashtable<String, Object>)environment.clone();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
environment = null;
|
||||
registry = null;
|
||||
// &&& If we were caching registry connections, we would probably
|
||||
// uncache this one now.
|
||||
}
|
||||
|
||||
public String getNameInNamespace() {
|
||||
return ""; // Registry has an empty name
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an RMI registry reference for this context.
|
||||
*<p>
|
||||
* If this context was created from a reference, that reference is
|
||||
* returned. Otherwise, an exception is thrown if the registry's
|
||||
* host is "localhost" or the default (null). Although this could
|
||||
* possibly make for a valid reference, it's far more likely to be
|
||||
* an easily made error.
|
||||
*
|
||||
* @see RegistryContextFactory
|
||||
*/
|
||||
public Reference getReference() throws NamingException {
|
||||
if (reference != null) {
|
||||
return (Reference)reference.clone(); // %%% clone the addrs too?
|
||||
}
|
||||
if (host == null || host.equals("localhost")) {
|
||||
throw (new ConfigurationException(
|
||||
"Cannot create a reference for an RMI registry whose " +
|
||||
"host was unspecified or specified as \"localhost\""));
|
||||
}
|
||||
String url = "rmi://";
|
||||
|
||||
// Enclose IPv6 literal address in '[' and ']'
|
||||
url = (host.indexOf(":") > -1) ? url + "[" + host + "]" :
|
||||
url + host;
|
||||
if (port > 0) {
|
||||
url += ":" + Integer.toString(port);
|
||||
}
|
||||
RefAddr addr = new StringRefAddr(RegistryContextFactory.ADDRESS_TYPE,
|
||||
url);
|
||||
return (new Reference(RegistryContext.class.getName(),
|
||||
addr,
|
||||
RegistryContextFactory.class.getName(),
|
||||
null));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a RemoteException inside a NamingException.
|
||||
*/
|
||||
public static NamingException wrapRemoteException(RemoteException re) {
|
||||
|
||||
NamingException ne;
|
||||
|
||||
if (re instanceof ConnectException) {
|
||||
ne = new ServiceUnavailableException();
|
||||
|
||||
} else if (re instanceof AccessException) {
|
||||
ne = new NoPermissionException();
|
||||
|
||||
} else if (re instanceof StubNotFoundException ||
|
||||
re instanceof UnknownHostException ||
|
||||
re instanceof SocketSecurityException) {
|
||||
ne = new ConfigurationException();
|
||||
|
||||
} else if (re instanceof ExportException ||
|
||||
re instanceof ConnectIOException ||
|
||||
re instanceof MarshalException ||
|
||||
re instanceof UnmarshalException ||
|
||||
re instanceof NoSuchObjectException) {
|
||||
ne = new CommunicationException();
|
||||
|
||||
} else if (re instanceof ServerException &&
|
||||
re.detail instanceof RemoteException) {
|
||||
ne = wrapRemoteException((RemoteException)re.detail);
|
||||
|
||||
} else {
|
||||
ne = new NamingException();
|
||||
}
|
||||
ne.setRootCause(re);
|
||||
return ne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registry at a given host, port and socket factory.
|
||||
* If "host" is null, uses default host.
|
||||
* If "port" is non-positive, uses default port.
|
||||
* If "socketFactory" is null, uses the default socket.
|
||||
*/
|
||||
private static Registry getRegistry(String host, int port,
|
||||
RMIClientSocketFactory socketFactory)
|
||||
throws NamingException
|
||||
{
|
||||
// %%% We could cache registry connections here. The transport layer
|
||||
// may already reuse connections.
|
||||
try {
|
||||
if (socketFactory == null) {
|
||||
return LocateRegistry.getRegistry(host, port);
|
||||
} else {
|
||||
return LocateRegistry.getRegistry(host, port, socketFactory);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)wrapRemoteException(e).fillInStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to install a security manager if none is currently in
|
||||
* place.
|
||||
*/
|
||||
private static void installSecurityMgr() {
|
||||
|
||||
try {
|
||||
System.setSecurityManager(new RMISecurityManager());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an object prior to binding it in the registry. First,
|
||||
* NamingManager.getStateToBind() is invoked. If the resulting
|
||||
* object is Remote, it is returned. If it is a Reference or
|
||||
* Referenceable, the reference is wrapped in a Remote object.
|
||||
* Otherwise, an exception is thrown.
|
||||
*
|
||||
* @param name The object's name relative to this context.
|
||||
*/
|
||||
private Remote encodeObject(Object obj, Name name)
|
||||
throws NamingException, RemoteException
|
||||
{
|
||||
obj = NamingManager.getStateToBind(obj, name, this, environment);
|
||||
|
||||
if (obj instanceof Remote) {
|
||||
return (Remote)obj;
|
||||
}
|
||||
if (obj instanceof Reference) {
|
||||
return (new ReferenceWrapper((Reference)obj));
|
||||
}
|
||||
if (obj instanceof Referenceable) {
|
||||
return (new ReferenceWrapper(((Referenceable)obj).getReference()));
|
||||
}
|
||||
throw (new IllegalArgumentException(
|
||||
"RegistryContext: " +
|
||||
"object to bind must be Remote, Reference, or Referenceable"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an object that has been retrieved from the registry.
|
||||
* First, if the object is a RemoteReference, the Reference is
|
||||
* unwrapped. Then, NamingManager.getObjectInstance() is invoked.
|
||||
*
|
||||
* @param name The object's name relative to this context.
|
||||
*/
|
||||
private Object decodeObject(Remote r, Name name) throws NamingException {
|
||||
try {
|
||||
Object obj = (r instanceof RemoteReference)
|
||||
? ((RemoteReference)r).getReference()
|
||||
: (Object)r;
|
||||
|
||||
/*
|
||||
* Classes may only be loaded from an arbitrary URL codebase when
|
||||
* the system property com.sun.jndi.rmi.object.trustURLCodebase
|
||||
* has been set to "true".
|
||||
*/
|
||||
|
||||
// Use 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 &&
|
||||
!trustURLCodebase) {
|
||||
throw new ConfigurationException(
|
||||
"The object factory is untrusted. Set the system property" +
|
||||
" 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.");
|
||||
}
|
||||
return NamingManager.getObjectInstance(obj, name, this,
|
||||
environment);
|
||||
} catch (NamingException e) {
|
||||
throw e;
|
||||
} catch (RemoteException e) {
|
||||
throw (NamingException)
|
||||
wrapRemoteException(e).fillInStackTrace();
|
||||
} catch (Exception e) {
|
||||
NamingException ne = new NamingException();
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A name parser for case-sensitive atomic names.
|
||||
*/
|
||||
class AtomicNameParser implements NameParser {
|
||||
private static final Properties syntax = new Properties();
|
||||
|
||||
public Name parse(String name) throws NamingException {
|
||||
return (new CompoundName(name, syntax));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An enumeration of name / class-name pairs.
|
||||
*/
|
||||
class NameClassPairEnumeration implements NamingEnumeration<NameClassPair> {
|
||||
private final String[] names;
|
||||
private int nextName; // index into "names"
|
||||
|
||||
NameClassPairEnumeration(String[] names) {
|
||||
this.names = names;
|
||||
nextName = 0;
|
||||
}
|
||||
|
||||
public boolean hasMore() {
|
||||
return (nextName < names.length);
|
||||
}
|
||||
|
||||
public NameClassPair next() throws NamingException {
|
||||
if (!hasMore()) {
|
||||
throw (new java.util.NoSuchElementException());
|
||||
}
|
||||
// Convert name to a one-element composite name, so embedded
|
||||
// meta-characters are properly escaped.
|
||||
String name = names[nextName++];
|
||||
Name cname = (new CompositeName()).add(name);
|
||||
NameClassPair ncp = new NameClassPair(cname.toString(),
|
||||
"java.lang.Object");
|
||||
ncp.setNameInNamespace(name);
|
||||
return ncp;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return hasMore();
|
||||
}
|
||||
|
||||
public NameClassPair nextElement() {
|
||||
try {
|
||||
return next();
|
||||
} catch (NamingException e) { // should never happen
|
||||
throw (new java.util.NoSuchElementException(
|
||||
"javax.naming.NamingException was thrown"));
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
nextName = names.length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An enumeration of Bindings.
|
||||
*
|
||||
* The actual registry lookups are performed when next() is called. It would
|
||||
* be nicer to defer this until the object (or its class name) is actually
|
||||
* requested. The problem with that approach is that Binding.getObject()
|
||||
* cannot throw NamingException.
|
||||
*/
|
||||
class BindingEnumeration implements NamingEnumeration<Binding> {
|
||||
private RegistryContext ctx;
|
||||
private final String[] names;
|
||||
private int nextName; // index into "names"
|
||||
|
||||
BindingEnumeration(RegistryContext ctx, String[] names) {
|
||||
// Clone ctx in case someone closes it before we're through.
|
||||
this.ctx = new RegistryContext(ctx);
|
||||
this.names = names;
|
||||
nextName = 0;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
public boolean hasMore() {
|
||||
if (nextName >= names.length) {
|
||||
ctx.close();
|
||||
}
|
||||
return (nextName < names.length);
|
||||
}
|
||||
|
||||
public Binding next() throws NamingException {
|
||||
if (!hasMore()) {
|
||||
throw (new java.util.NoSuchElementException());
|
||||
}
|
||||
// Convert name to a one-element composite name, so embedded
|
||||
// meta-characters are properly escaped.
|
||||
String name = names[nextName++];
|
||||
Name cname = (new CompositeName()).add(name);
|
||||
|
||||
Object obj = ctx.lookup(cname);
|
||||
String cnameStr = cname.toString();
|
||||
Binding binding = new Binding(cnameStr, obj);
|
||||
binding.setNameInNamespace(cnameStr);
|
||||
return binding;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return hasMore();
|
||||
}
|
||||
|
||||
public Binding nextElement() {
|
||||
try {
|
||||
return next();
|
||||
} catch (NamingException e) {
|
||||
throw (new java.util.NoSuchElementException(
|
||||
"javax.naming.NamingException was thrown"));
|
||||
}
|
||||
}
|
||||
|
||||
public void close () {
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.rmi.registry;
|
||||
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.*;
|
||||
import javax.naming.spi.*;
|
||||
|
||||
import com.sun.jndi.url.rmi.rmiURLContextFactory;
|
||||
|
||||
/**
|
||||
* A RegistryContextFactory takes an RMI registry reference, and
|
||||
* creates the corresponding RMI object or registry context. In
|
||||
* addition, it serves as the initial context factory when using an
|
||||
* RMI registry as an initial context.
|
||||
*<p>
|
||||
* When an initial context is being created, the environment
|
||||
* property "java.naming.provider.url" should contain the RMI URL of
|
||||
* the appropriate registry. Otherwise, the default URL "rmi:" is used.
|
||||
*<p>
|
||||
* An RMI registry reference contains one or more StringRefAddrs of
|
||||
* type "URL", each containing a single RMI URL. Other addresses
|
||||
* are ignored. Multiple URLs represent alternative addresses for the
|
||||
* same logical resource. The order of the addresses is not significant.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public class RegistryContextFactory
|
||||
implements ObjectFactory, InitialContextFactory
|
||||
{
|
||||
/**
|
||||
* The type of each address in an RMI registry reference.
|
||||
*/
|
||||
public final static String ADDRESS_TYPE = "URL";
|
||||
|
||||
public Context getInitialContext(Hashtable<?,?> env) throws NamingException {
|
||||
|
||||
if (env != null) {
|
||||
env = (Hashtable) env.clone();
|
||||
}
|
||||
return URLToContext(getInitCtxURL(env), env);
|
||||
}
|
||||
|
||||
public Object getObjectInstance(Object ref, Name name, Context nameCtx,
|
||||
Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
if (!isRegistryRef(ref)) {
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* No need to clone env here. If getObjectInstance()
|
||||
* returns something other than a RegistryContext (which
|
||||
* happens if you're looking up an object bound in the
|
||||
* registry, as opposed to looking up the registry itself),
|
||||
* then the context is GCed right away and there's no need to
|
||||
* clone the environment. If getObjectInstance() returns a
|
||||
* RegistryContext, then it still goes through
|
||||
* GenericURLContext, which calls RegistryContext.lookup()
|
||||
* with an empty name, which clones the environment.
|
||||
*/
|
||||
Object obj = URLsToObject(getURLs((Reference)ref), env);
|
||||
if (obj instanceof RegistryContext) {
|
||||
RegistryContext ctx = (RegistryContext)obj;
|
||||
ctx.reference = (Reference)ref;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static Context URLToContext(String url, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
rmiURLContextFactory factory = new rmiURLContextFactory();
|
||||
Object obj = factory.getObjectInstance(url, null, null, env);
|
||||
|
||||
if (obj instanceof Context) {
|
||||
return (Context)obj;
|
||||
} else {
|
||||
throw (new NotContextException(url));
|
||||
}
|
||||
}
|
||||
|
||||
private static Object URLsToObject(String[] urls, Hashtable<?,?> env)
|
||||
throws NamingException
|
||||
{
|
||||
rmiURLContextFactory factory = new rmiURLContextFactory();
|
||||
return factory.getObjectInstance(urls, null, null, env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads environment to find URL of initial context.
|
||||
* The default URL is "rmi:".
|
||||
*/
|
||||
private static String getInitCtxURL(Hashtable<?,?> env) {
|
||||
|
||||
final String defaultURL = "rmi:";
|
||||
|
||||
String url = null;
|
||||
if (env != null) {
|
||||
url = (String)env.get(Context.PROVIDER_URL);
|
||||
}
|
||||
return ((url != null) ? url : defaultURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if argument is an RMI registry reference.
|
||||
*/
|
||||
private static boolean isRegistryRef(Object obj) {
|
||||
|
||||
if (!(obj instanceof Reference)) {
|
||||
return false;
|
||||
}
|
||||
String thisClassName = RegistryContextFactory.class.getName();
|
||||
Reference ref = (Reference)obj;
|
||||
|
||||
return thisClassName.equals(ref.getFactoryClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URLs contained within an RMI registry reference.
|
||||
*/
|
||||
private static String[] getURLs(Reference ref) throws NamingException {
|
||||
|
||||
int size = 0; // number of URLs
|
||||
String[] urls = new String[ref.size()];
|
||||
|
||||
Enumeration<RefAddr> addrs = ref.getAll();
|
||||
while (addrs.hasMoreElements()) {
|
||||
RefAddr addr = addrs.nextElement();
|
||||
|
||||
if ((addr instanceof StringRefAddr) &&
|
||||
addr.getType().equals(ADDRESS_TYPE)) {
|
||||
|
||||
urls[size++] = (String)addr.getContent();
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
throw (new ConfigurationException(
|
||||
"Reference contains no valid addresses"));
|
||||
}
|
||||
|
||||
// Trim URL array down to size.
|
||||
if (size == ref.size()) {
|
||||
return urls;
|
||||
}
|
||||
String[] urls2 = new String[size];
|
||||
System.arraycopy(urls, 0, urls2, 0, size);
|
||||
return urls2;
|
||||
}
|
||||
}
|
||||
44
jdkSrc/jdk8/com/sun/jndi/rmi/registry/RemoteReference.java
Normal file
44
jdkSrc/jdk8/com/sun/jndi/rmi/registry/RemoteReference.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.rmi.registry;
|
||||
|
||||
|
||||
import java.rmi.*;
|
||||
|
||||
import javax.naming.*;
|
||||
|
||||
|
||||
/**
|
||||
* The RemoteReference interface wraps a Reference in a Remote wrapper.
|
||||
*
|
||||
* @author Scott Seligman
|
||||
*/
|
||||
|
||||
|
||||
public interface RemoteReference extends Remote {
|
||||
|
||||
Reference getReference() throws NamingException, RemoteException;
|
||||
}
|
||||
301
jdkSrc/jdk8/com/sun/jndi/toolkit/corba/CorbaUtils.java
Normal file
301
jdkSrc/jdk8/com/sun/jndi/toolkit/corba/CorbaUtils.java
Normal 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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
692
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/AtomicContext.java
Normal file
692
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/AtomicContext.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
393
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/AtomicDirContext.java
Normal file
393
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/AtomicDirContext.java
Normal 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;
|
||||
}
|
||||
}
|
||||
805
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/ComponentContext.java
Normal file
805
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/ComponentContext.java
Normal 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);
|
||||
*
|
||||
*/
|
||||
470
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/ComponentDirContext.java
Normal file
470
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/ComponentDirContext.java
Normal 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;
|
||||
}
|
||||
}
|
||||
442
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/Continuation.java
Normal file
442
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/Continuation.java
Normal 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;
|
||||
}
|
||||
65
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/HeadTail.java
Normal file
65
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/HeadTail.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
63
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/StringHeadTail.java
Normal file
63
jdkSrc/jdk8/com/sun/jndi/toolkit/ctx/StringHeadTail.java
Normal 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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user