blob: cfc87ac86658fee7ce6a6019c4aab595015d41fb [file] [log] [blame]
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.enterprise.adaptor.ad;
import com.google.common.annotations.VisibleForTesting;
import java.io.*;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
/**
* Mock of {@link LdapContext}.
*/
public class MockLdapContext extends InitialLdapContext {
private BasicAttributes attributes = new BasicAttributes();
private Hashtable<String, Object> searchResults
= new Hashtable<String, Object>();
@VisibleForTesting
Control[] controls = new Control[0];
public MockLdapContext() throws NamingException {
}
@Override
public Attributes getAttributes(String name) throws NamingException {
return attributes;
}
/** Normal way to add things to this Mock */
public MockLdapContext addKey(String key, Object value) {
attributes.put(key, value);
return this;
}
public MockLdapContext removeKey(String key) {
attributes.remove(key);
return this;
}
public static String makeKey(String filter, String attribute, String baseDn) {
return filter + "|" + attribute + "|" + baseDn;
}
public MockLdapContext addSearchResult(String filter,
String attribute, String baseDn, Object value) {
searchResults.put(makeKey(filter, attribute, baseDn), value);
return this;
}
/** Returns a <code>NamingEnumeration</code> of <code>SearchResult</code>s */
public NamingEnumeration<SearchResult> search(String base, String filter,
SearchControls searchControls) throws NamingException {
Vector<SearchResult> results = new Vector<SearchResult>();
SearchResult currentResult = null;
for (String attribute : searchControls.getReturningAttributes()) {
Object o = searchResults.get(makeKey(filter, attribute, base));
if (o == null) {
// hack to make search for member;Range=X-Y succeed when that's the
// final range present
if (attribute.startsWith("member;Range=")) {
attribute += "*";
o = searchResults.get(makeKey(filter, attribute, base));
}
}
if (o != null) {
if (currentResult == null) {
currentResult = makeSearchResult(attribute, o, base);
results.add(currentResult);
} else {
Attributes attrs = currentResult.getAttributes();
this.addAttribute(attrs, attribute, o);
currentResult.setAttributes(attrs);
}
}
}
return new SearchResultsNamingEnumeration(results);
}
/** properly handle collections as we add a new attribute */
private static void addAttribute(Attributes attrs, String newAttr,
Object value) {
attrs.put(newAttr, value);
if (value instanceof Collection<?>) {
Attribute attr = attrs.get(newAttr);
attr.clear();
for (Object member: (Collection<?>) value) {
attr.add(member);
}
}
}
/** Creates a <code>SearchResults</code> wrapper with a single attribute */
private static SearchResult makeSearchResult(String attribute, Object o,
String baseDn) {
SearchResult sr = new SearchResult("search result name", o,
new BasicAttributes());
addAttribute(sr.getAttributes(), attribute, o);
sr.setNameInNamespace("cn=name\\ under," + baseDn);
return sr;
}
@Override
public Control[] getResponseControls() throws NamingException {
return controls;
};
/** Sets the controls (which this class does nothing with) */
@Override
public void setRequestControls(Control[] requestControls)
throws NamingException {
controls = requestControls;
};
@VisibleForTesting
static class SearchResultsNamingEnumeration
implements NamingEnumeration<SearchResult> {
private final Enumeration<SearchResult> results;
private SearchResult nextElement = null;
SearchResultsNamingEnumeration(Vector<SearchResult> results) {
this.results = results.elements();
}
private SearchResult getNextElement() {
if (results.hasMoreElements()) {
return results.nextElement();
}
return null;
}
public boolean hasMore() {
if (nextElement != null) {
return true;
}
nextElement = getNextElement();
return (nextElement != null);
}
public boolean hasMoreElements() {
return hasMore();
}
public SearchResult next() {
if (!hasMore()) {
throw new NoSuchElementException();
}
SearchResult res = nextElement;
nextElement = null;
return res;
}
public SearchResult nextElement() {
return next();
}
public void close() {
}
}
}