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

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

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
/**
* Is implemented by classes that can perform filter checks on
* an attribute set.
*/
public interface AttrFilter {
/**
* Determines whether an attribute passes the filter.
*/
public boolean check(Attributes targetAttrs) throws NamingException;
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Supports checking an attribute set satisfies a filter
* that is specified as a set of "matching" attributes.
* Checking is done by determining whether the given attribute set
* is a superset of the matching ones.
*
* @author Rosanna Lee
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.*;
public class ContainmentFilter implements AttrFilter {
private Attributes matchingAttrs;
public ContainmentFilter(Attributes match) {
matchingAttrs = match;
}
public boolean check(Attributes attrs) throws NamingException {
return matchingAttrs == null ||
matchingAttrs.size() == 0 ||
contains(attrs, matchingAttrs);
}
// returns true if superset contains subset
public static boolean contains(Attributes superset, Attributes subset)
throws NamingException {
if (subset == null)
return true; // an empty set is always a subset
NamingEnumeration<? extends Attribute> m = subset.getAll();
while (m.hasMore()) {
if (superset == null) {
return false; // contains nothing
}
Attribute target = m.next();
Attribute fromSuper = superset.get(target.getID());
if (fromSuper == null) {
return false;
} else {
// check whether attribute values match
if (target.size() > 0) {
NamingEnumeration<?> vals = target.getAll();
while (vals.hasMore()) {
if (!fromSuper.contains(vals.next())) {
return false;
}
}
}
}
}
return true;
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.SearchControls;
import java.util.*;
/**
* A class for recursively enumerating the contents of a Context;
*
* @author Jon Ruiz
*/
public class ContextEnumerator implements NamingEnumeration<Binding> {
private static boolean debug = false;
private NamingEnumeration<Binding> children = null;
private Binding currentChild = null;
private boolean currentReturned = false;
private Context root;
private ContextEnumerator currentChildEnum = null;
private boolean currentChildExpanded = false;
private boolean rootProcessed = false;
private int scope = SearchControls.SUBTREE_SCOPE;
private String contextName = "";
public ContextEnumerator(Context context) throws NamingException {
this(context, SearchControls.SUBTREE_SCOPE);
}
public ContextEnumerator(Context context, int scope)
throws NamingException {
// return this object except when searching single-level
this(context, scope, "", scope != SearchControls.ONELEVEL_SCOPE);
}
protected ContextEnumerator(Context context, int scope, String contextName,
boolean returnSelf)
throws NamingException {
if(context == null) {
throw new IllegalArgumentException("null context passed");
}
root = context;
// No need to list children if we're only searching object
if (scope != SearchControls.OBJECT_SCOPE) {
children = getImmediateChildren(context);
}
this.scope = scope;
this.contextName = contextName;
// pretend root is processed, if we're not supposed to return ourself
rootProcessed = !returnSelf;
prepNextChild();
}
// Subclass should override if it wants to avoid calling obj factory
protected NamingEnumeration<Binding> getImmediateChildren(Context ctx)
throws NamingException {
return ctx.listBindings("");
}
// Subclass should override so that instance is of same type as subclass
protected ContextEnumerator newEnumerator(Context ctx, int scope,
String contextName, boolean returnSelf) throws NamingException {
return new ContextEnumerator(ctx, scope, contextName, returnSelf);
}
public boolean hasMore() throws NamingException {
return !rootProcessed ||
(scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants());
}
public boolean hasMoreElements() {
try {
return hasMore();
} catch (NamingException e) {
return false;
}
}
public Binding nextElement() {
try {
return next();
} catch (NamingException e) {
throw new NoSuchElementException(e.toString());
}
}
public Binding next() throws NamingException {
if (!rootProcessed) {
rootProcessed = true;
return new Binding("", root.getClass().getName(),
root, true);
}
if (scope != SearchControls.OBJECT_SCOPE && hasMoreDescendants()) {
return getNextDescendant();
}
throw new NoSuchElementException();
}
public void close() throws NamingException {
root = null;
}
private boolean hasMoreChildren() throws NamingException {
return children != null && children.hasMore();
}
private Binding getNextChild() throws NamingException {
Binding oldBinding = children.next();
Binding newBinding = null;
// if the name is relative, we need to add it to the name of this
// context to keep it relative w.r.t. the root context we are
// enumerating
if(oldBinding.isRelative() && !contextName.equals("")) {
NameParser parser = root.getNameParser("");
Name newName = parser.parse(contextName);
newName.add(oldBinding.getName());
if(debug) {
System.out.println("ContextEnumerator: adding " + newName);
}
newBinding = new Binding(newName.toString(),
oldBinding.getClassName(),
oldBinding.getObject(),
oldBinding.isRelative());
} else {
if(debug) {
System.out.println("ContextEnumerator: using old binding");
}
newBinding = oldBinding;
}
return newBinding;
}
private boolean hasMoreDescendants() throws NamingException {
// if the current child is expanded, see if it has more elements
if (!currentReturned) {
if(debug) {System.out.println("hasMoreDescendants returning " +
(currentChild != null) ); }
return currentChild != null;
} else if (currentChildExpanded && currentChildEnum.hasMore()) {
if(debug) {System.out.println("hasMoreDescendants returning " +
"true");}
return true;
} else {
if(debug) {System.out.println("hasMoreDescendants returning " +
"hasMoreChildren");}
return hasMoreChildren();
}
}
private Binding getNextDescendant() throws NamingException {
if (!currentReturned) {
// returning parent
if(debug) {System.out.println("getNextDescedant: simple case");}
currentReturned = true;
return currentChild;
} else if (currentChildExpanded && currentChildEnum.hasMore()) {
if(debug) {System.out.println("getNextDescedant: expanded case");}
// if the current child is expanded, use it's enumerator
return currentChildEnum.next();
} else {
// Ready to go onto next child
if(debug) {System.out.println("getNextDescedant: next case");}
prepNextChild();
return getNextDescendant();
}
}
private void prepNextChild() throws NamingException {
if(hasMoreChildren()) {
try {
currentChild = getNextChild();
currentReturned = false;
} catch (NamingException e){
if (debug) System.out.println(e);
if (debug) e.printStackTrace();
}
} else {
currentChild = null;
return;
}
if(scope == SearchControls.SUBTREE_SCOPE &&
currentChild.getObject() instanceof Context) {
currentChildEnum = newEnumerator(
(Context)(currentChild.getObject()),
scope, currentChild.getName(),
false);
currentChildExpanded = true;
if(debug) {System.out.println("prepNextChild: expanded");}
} else {
currentChildExpanded = false;
currentChildEnum = null;
if(debug) {System.out.println("prepNextChild: normal");}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.*;
/**
* A class for searching DirContexts
*
* @author Jon Ruiz
*/
public class DirSearch {
public static NamingEnumeration<SearchResult> search(DirContext ctx,
Attributes matchingAttributes,
String[] attributesToReturn) throws NamingException {
SearchControls cons = new SearchControls(
SearchControls.ONELEVEL_SCOPE,
0, 0, attributesToReturn,
false, false);
return new LazySearchEnumerationImpl(
new ContextEnumerator(ctx, SearchControls.ONELEVEL_SCOPE),
new ContainmentFilter(matchingAttributes),
cons);
}
public static NamingEnumeration<SearchResult> search(DirContext ctx,
String filter, SearchControls cons) throws NamingException {
if (cons == null)
cons = new SearchControls();
return new LazySearchEnumerationImpl(
new ContextEnumerator(ctx, cons.getSearchScope()),
new SearchFilter(filter),
cons);
}
public static NamingEnumeration<SearchResult> search(DirContext ctx,
String filterExpr, Object[] filterArgs, SearchControls cons)
throws NamingException {
String strfilter = SearchFilter.format(filterExpr, filterArgs);
return search(ctx, strfilter, cons);
}
}

View File

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

View File

@@ -0,0 +1,184 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Given an enumeration of candidates, check whether each
* item in enumeration satifies the given filter.
* Each item is a Binding and the following is used to get its
* attributes for used by the filter:
*
* ((DirContext)item.getObject()).getAttributes("").
* If item.getObject() is not an DirContext, the item is skipped
*
* The items in the enumeration are obtained one at a time as
* items from the search enumeration are requested.
*
* @author Rosanna Lee
*/
package com.sun.jndi.toolkit.dir;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.DirectoryManager;
import java.util.NoSuchElementException;
import java.util.Hashtable;
final public class LazySearchEnumerationImpl
implements NamingEnumeration<SearchResult> {
private NamingEnumeration<Binding> candidates;
private SearchResult nextMatch = null;
private SearchControls cons;
private AttrFilter filter;
private Context context;
private Hashtable<String, Object> env;
private boolean useFactory = true;
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons) throws NamingException {
this.candidates = candidates;
this.filter = filter;
if(cons == null) {
this.cons = new SearchControls();
} else {
this.cons = cons;
}
}
@SuppressWarnings("unchecked") // For Hashtable clone: env.clone()
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons,
Context ctx, Hashtable<String, Object> env, boolean useFactory)
throws NamingException {
this.candidates = candidates;
this.filter = filter;
this.env = (Hashtable<String, Object>)
((env == null) ? null : env.clone());
this.context = ctx;
this.useFactory = useFactory;
if(cons == null) {
this.cons = new SearchControls();
} else {
this.cons = cons;
}
}
public LazySearchEnumerationImpl(NamingEnumeration<Binding> candidates,
AttrFilter filter, SearchControls cons,
Context ctx, Hashtable<String, Object> env) throws NamingException {
this(candidates, filter, cons, ctx, env, true);
}
public boolean hasMore() throws NamingException {
// find and do not remove from list
return findNextMatch(false) != null;
}
public boolean hasMoreElements() {
try {
return hasMore();
} catch (NamingException e) {
return false;
}
}
public SearchResult nextElement() {
try {
return findNextMatch(true);
} catch (NamingException e) {
throw new NoSuchElementException(e.toString());
}
}
public SearchResult next() throws NamingException {
// find and remove from list
return (findNextMatch(true));
}
public void close() throws NamingException {
if (candidates != null) {
candidates.close();
}
}
private SearchResult findNextMatch(boolean remove) throws NamingException {
SearchResult answer;
if (nextMatch != null) {
answer = nextMatch;
if (remove) {
nextMatch = null;
}
return answer;
} else {
// need to find next match
Binding next;
Object obj;
Attributes targetAttrs;
while (candidates.hasMore()) {
next = candidates.next();
obj = next.getObject();
if (obj instanceof DirContext) {
targetAttrs = ((DirContext)(obj)).getAttributes("");
if (filter.check(targetAttrs)) {
if (!cons.getReturningObjFlag()) {
obj = null;
} else if (useFactory) {
try {
// Give name only if context non-null,
// otherewise, name will be interpreted relative
// to initial context (not what we want)
Name nm = (context != null ?
new CompositeName(next.getName()) : null);
obj = DirectoryManager.getObjectInstance(obj,
nm, context, env, targetAttrs);
} catch (NamingException e) {
throw e;
} catch (Exception e) {
NamingException e2 = new NamingException(
"problem generating object using object factory");
e2.setRootCause(e);
throw e2;
}
}
answer = new SearchResult(next.getName(),
next.getClassName(), obj,
SearchFilter.selectAttributes(targetAttrs,
cons.getReturningAttributes()),
true);
if (!remove)
nextMatch = answer;
return answer;
}
}
}
return null;
}
}
}

View File

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