/**
* Copyright 2009 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.safehaus.penrose.partition;
import org.safehaus.penrose.acl.ACLEvaluator;
import org.safehaus.penrose.adapter.AdapterManager;
import org.safehaus.penrose.connection.ConnectionManager;
import org.safehaus.penrose.directory.Directory;
import org.safehaus.penrose.directory.Entry;
import org.safehaus.penrose.interpreter.DefaultInterpreter;
import org.safehaus.penrose.interpreter.Interpreter;
import org.safehaus.penrose.ldap.*;
import org.safehaus.penrose.mapping.MappingManager;
import org.safehaus.penrose.module.Module;
import org.safehaus.penrose.module.ModuleChain;
import org.safehaus.penrose.module.ModuleManager;
import org.safehaus.penrose.naming.PenroseContext;
import org.safehaus.penrose.scheduler.Scheduler;
import org.safehaus.penrose.scheduler.SchedulerConfig;
import org.safehaus.penrose.scheduler.SchedulerContext;
import org.safehaus.penrose.schema.ObjectClass;
import org.safehaus.penrose.schema.SchemaManager;
import org.safehaus.penrose.session.Session;
import org.safehaus.penrose.operation.SearchOperation;
import org.safehaus.penrose.operation.PipelineSearchOperation;
import org.safehaus.penrose.source.SourceManager;
import org.safehaus.penrose.thread.ThreadManager;
import org.safehaus.penrose.thread.ThreadManagerConfig;
import org.safehaus.penrose.Penrose;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ietf.ldap.LDAPException;
import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
/**
* @author Endi S. Dewata
*/
public class Partition implements Cloneable {
public Logger log = LoggerFactory.getLogger(getClass());
public final static String STARTING = "STARTING";
public final static String STARTED = "STARTED";
public final static String STOPPING = "STOPPING";
public final static String STOPPED = "STOPPED";
public final static String SCHEMA_CHECKING = "schemaChecking";
public final static boolean DEFAULT_SCHEMA_CHECKING = false; // disabled
protected PartitionConfig partitionConfig;
protected PartitionContext partitionContext;
protected AdapterManager adapterManager;
protected ConnectionManager connectionManager;
protected SourceManager sourceManager;
protected MappingManager mappingManager;
protected Directory directory;
protected ModuleManager moduleManager;
protected Scheduler scheduler;
protected ThreadManager threadManager;
protected SchemaManager schemaManager;
protected ACLEvaluator aclEvaluator;
protected boolean schemaChecking;
protected String status = STOPPED;
public Partition() {
}
public synchronized void init(PartitionConfig partitionConfig, PartitionContext partitionContext) throws Exception {
//log.debug("Initializing "+partitionConfig.getName()+" partition.");
if (STARTING.equals(status)) return;
status = STARTING;
this.partitionConfig = partitionConfig;
this.partitionContext = partitionContext;
PenroseContext penroseContext = partitionContext.getPenroseContext();
schemaManager = penroseContext.getSchemaManager();
threadManager = createThreadManager(partitionConfig.getThreadManagerConfig());
aclEvaluator = new ACLEvaluator();
aclEvaluator.init(this);
adapterManager = new AdapterManager();
adapterManager.init(this);
connectionManager = new ConnectionManager(this);
connectionManager.init();
sourceManager = new SourceManager(this);
sourceManager.init();
mappingManager = new MappingManager(this);
mappingManager.init();
directory = new Directory(this);
directory.init();
moduleManager = new ModuleManager(this);
moduleManager.init();
scheduler = createScheduler(partitionConfig.getSchedulerConfig());
String s = getParameter(SCHEMA_CHECKING);
schemaChecking = s == null ? DEFAULT_SCHEMA_CHECKING : Boolean.valueOf(s);
init();
status = STARTED;
//log.debug("Partition "+partitionConfig.getName()+" started.");
}
public void init() throws Exception {
}
public void destroy() throws Exception {
//log.debug("Stopping "+partitionConfig.getName()+" partition.");
if (STOPPING.equals(status)) return;
status = STOPPING;
if (scheduler != null) scheduler.destroy();
if (threadManager != null) threadManager.destroy();
moduleManager.destroy();
directory.destroy();
mappingManager.destroy();
sourceManager.destroy();
connectionManager.destroy();
partitionContext.destroy();
status = STOPPED;
//log.debug("Partition "+partitionConfig.getName()+" stopped.");
}
public String getName() {
return partitionConfig.getName();
}
public void setName(String name) {
partitionConfig.setName(name);
}
public String getDescription() {
return partitionConfig.getDescription();
}
public void setDescription(String description) {
partitionConfig.setDescription(description);
}
public String getStatus() {
return status;
}
public Map<String,String> getParameters() {
return partitionConfig.getParameters();
}
public Collection<String> getParameterNames() {
return partitionConfig.getParameterNames();
}
public String getParameter(String name) {
return partitionConfig.getParameter(name);
}
public boolean isEnabled() {
return partitionConfig.isEnabled();
}
public PartitionConfig getPartitionConfig() {
return partitionConfig;
}
public void setPartitionConfig(PartitionConfig partitionConfig) {
this.partitionConfig = partitionConfig;
}
public String toString() {
return partitionConfig.getName();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Managers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ConnectionManager getConnectionManager() {
return connectionManager;
}
public SourceManager getSourceManager() {
return sourceManager;
}
public MappingManager getMappingManager() {
return mappingManager;
}
public Directory getDirectory() {
return directory;
}
public ModuleManager getModuleManager() {
return moduleManager;
}
public Scheduler createScheduler(SchedulerConfig schedulerConfig) throws Exception {
if (schedulerConfig == null) return null;
if (!schedulerConfig.isEnabled()) return null;
String className = schedulerConfig.getSchedulerClass();
ClassLoader cl = partitionContext.getClassLoader();
Class clazz = cl.loadClass(className);
Scheduler scheduler = (Scheduler)clazz.newInstance();
SchedulerContext schedulerContext = new SchedulerContext();
schedulerContext.setPartition(this);
scheduler.init(schedulerConfig, schedulerContext);
return scheduler;
}
public ThreadManager createThreadManager(ThreadManagerConfig threadManagerConfig) throws Exception {
if (threadManagerConfig == null) return null;
if (!threadManagerConfig.isEnabled()) return null;
Class clazz;
String className = threadManagerConfig.getThreadManagerClass();
if (className == null) {
clazz = ThreadManager.class;
} else {
ClassLoader cl = partitionContext.getClassLoader();
clazz = cl.loadClass(className);
}
Constructor constructor = clazz.getConstructor(String.class);
ThreadManager threadManager = (ThreadManager)constructor.newInstance(Penrose.PRODUCT_NAME+"-"+partitionConfig.getName());
threadManager.init(threadManagerConfig);
return threadManager;
}
public PartitionContext getPartitionContext() {
return partitionContext;
}
public void setPartitionContext(PartitionContext partitionContext) {
this.partitionContext = partitionContext;
}
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public Object clone() throws CloneNotSupportedException {
Partition partition = (Partition)super.clone();
partition.partitionConfig = (PartitionConfig)partitionConfig.clone();
partition.partitionContext = partitionContext;
return partition;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Modules
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public ModuleChain createModuleChain(Entry entry, Collection<Module> modules) {
ModuleChain lastChain = new ModuleChain(entry);
Iterator<Module> i = modules.iterator();
return createModuleChain(entry, i, lastChain);
}
public ModuleChain createModuleChain(Entry entry, Iterator<Module> i, ModuleChain lastChain) {
if (!i.hasNext()) return lastChain;
Module module = i.next();
ModuleChain nextChain = createModuleChain(entry, i, lastChain);
return new ModuleChain(entry, module, nextChain);
}
public Collection<Module> findModules(DN dn) throws Exception {
return moduleManager.findModules(dn);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Normalize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void normalize(AddRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
Attributes attributes = schemaManager.normalize(request.getAttributes());
request.setAttributes(attributes);
}
public void normalize(BindRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
}
public void normalize(CompareRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
String attributeName = schemaManager.normalizeAttributeName(request.getAttributeName());
request.setAttributeName(attributeName);
}
public void normalize(DeleteRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
}
public void normalize(ModifyRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
Collection<Modification> modifications = schemaManager.normalizeModifications(request.getModifications());
request.setModifications(modifications);
}
public void normalize(ModRdnRequest request) throws Exception {
DN dn = schemaManager.normalize(request.getDn());
request.setDn(dn);
RDN newRdn = schemaManager.normalize(request.getNewRdn());
request.setNewRdn(newRdn);
}
public void normalize(SearchRequest request) throws Exception {
DN baseDn = schemaManager.normalize(request.getDn());
request.setDn(baseDn);
Collection<String> requestedAttributes = schemaManager.normalize(request.getAttributes());
request.setAttributes(requestedAttributes);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ACL
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void validatePermission(Session session, AddRequest request, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = request.getDn();
DN parentDn = dn.getParentDn();
Entry parent = entry.getParent();
int rc = aclEvaluator.checkAdd(session, parent, parentDn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to add entry under \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(Session session, CompareRequest request, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = request.getDn();
int rc = aclEvaluator.checkRead(session, entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to compare entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(Session session, DeleteRequest request, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = request.getDn();
int rc = aclEvaluator.checkDelete(session, entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to delete entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(Session session, ModifyRequest request, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = request.getDn();
int rc = aclEvaluator.checkWrite(session, entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to modify entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(Session session, ModRdnRequest request, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = request.getDn();
int rc = aclEvaluator.checkWrite(session, entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to rename entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(SearchOperation operation, Entry entry) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = operation.getDn();
int rc = aclEvaluator.checkSearch(operation.getSession(), entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to search entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
public void validatePermission(SearchOperation operation, SearchResult result) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = result.getDn();
String entryId = result.getEntryName();
Entry entry = directory.getEntry(entryId);
int rc = aclEvaluator.checkRead(operation.getSession(), entry, dn);
if (rc == LDAP.SUCCESS) return;
if (debug) log.debug("Not allowed to read entry \""+dn+"\".");
throw LDAP.createException(LDAP.INSUFFICIENT_ACCESS_RIGHTS);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Schema
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void validateSchema(AddRequest request, Entry entry) throws Exception {
if (!schemaChecking) return;
Collection<ObjectClass> objectClasses = schemaManager.getObjectClasses(entry);
Attributes attributes = request.getAttributes();
for (Attribute attribute : attributes.getAll()) {
String attributeName = attribute.getName();
boolean found = false;
for (ObjectClass oc : objectClasses) {
if (oc.getName().equalsIgnoreCase("extensibleObject")) {
found = true;
break;
}
if (oc.containsRequiredAttribute(attributeName)) {
found = true;
break;
}
if (oc.containsOptionalAttribute(attributeName)) {
found = true;
break;
}
}
if (!found) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
}
for (ObjectClass oc : objectClasses) {
for (String attributeName : oc.getRequiredAttributes()) {
if (attributes.get(attributeName) == null) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
}
}
}
public void validateSchema(ModifyRequest request, Entry entry) throws Exception {
if (!schemaChecking) return;
Collection<ObjectClass> objectClasses = schemaManager.getObjectClasses(entry);
Collection<Modification> modifications = request.getModifications();
for (Modification modification : modifications) {
int type = modification.getType();
Attribute attribute = modification.getAttribute();
String attributeName = attribute.getName();
if (type == Modification.ADD) {
boolean found = false;
for (ObjectClass oc : objectClasses) {
if (oc.getName().equalsIgnoreCase("extensibleObject")) {
found = true;
break;
}
if (oc.containsRequiredAttribute(attributeName)) {
found = true;
break;
}
if (oc.containsOptionalAttribute(attributeName)) {
found = true;
break;
}
}
if (!found) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
} else if (type == Modification.DELETE && attribute.isEmpty()) {
boolean found = false;
for (ObjectClass oc : objectClasses) {
if (oc.containsRequiredAttribute(attributeName)) {
found = true;
break;
}
}
if (found) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
}
}
}
public void validateSchema(ModRdnRequest request, Entry entry) throws Exception {
if (!schemaChecking) return;
Collection<ObjectClass> objectClasses = schemaManager.getObjectClasses(entry);
RDN newRdn = request.getNewRdn();
for (String attributeName : newRdn.getNames()) {
boolean found = false;
for (ObjectClass oc : objectClasses) {
if (oc.getName().equalsIgnoreCase("extensibleObject")) {
found = true;
break;
}
if (oc.containsRequiredAttribute(attributeName)) {
found = true;
break;
}
if (oc.containsOptionalAttribute(attributeName)) {
found = true;
break;
}
}
if (!found) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
}
for (String attributeName : newRdn.getNames()) {
for (ObjectClass oc : objectClasses) {
if (oc.containsRequiredAttribute(attributeName)) {
throw LDAP.createException(LDAP.OBJECT_CLASS_VIOLATION);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Add
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void add(
Session session,
AddRequest request,
AddResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Adding " + dn + " into " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.add(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Bind
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void bind(
Session session,
BindRequest request,
BindResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
boolean found = false;
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Binding " + dn + " in " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.bind(session, request, response);
return; // return after the first successful operation
} catch (LDAPException e) {
log.debug(e.getMessage());
if (e.getResultCode() == LDAP.INVALID_CREDENTIALS) found = true;
exception = e;
} catch (Exception e) {
Penrose.errorLog.error(e.getMessage(), e);
exception = e;
}
}
if (found) throw LDAP.createException(LDAP.INVALID_CREDENTIALS);
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compare
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void compare(
Session session,
CompareRequest request,
CompareResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Comparing " + dn + " in " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.compare(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Delete
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void delete(
Session session,
DeleteRequest request,
DeleteResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Deleting " + dn + " from " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.delete(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public List<Entry> findEntries(DN dn) throws Exception {
return directory.findEntries(dn);
}
public SearchResult find(Session session, DN dn) throws Exception {
boolean debug = log.isDebugEnabled();
if (debug) log.debug("Finding "+dn);
SearchRequest request = new SearchRequest();
request.setDn(dn);
request.setScope(SearchRequest.SCOPE_BASE);
SearchResponse response = new SearchResponse();
search(session, request, response);
int rc = response.waitFor();
if (rc != LDAP.SUCCESS) {
if (debug) log.debug("Entry "+dn+" not found: "+response.getErrorMessage());
throw LDAP.createException(rc);
}
if (!response.hasNext()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
SearchResult result = response.next();
if (debug) log.debug("Found entry "+dn+".");
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Modify
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void modify(
Session session,
ModifyRequest request,
ModifyResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Modifying " + dn + " in " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.modify(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ModRdn
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void modrdn(
Session session,
ModRdnRequest request,
ModRdnResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
normalize(request);
DN dn = request.getDn();
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Renaming " + dn + " in " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.modrdn(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Search
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void search(
Session session,
SearchRequest request,
SearchResponse response
) throws Exception {
try {
SearchOperation operation = session.createSearchOperation(""+request.getMessageId(), request, response);
search(operation);
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
public void search(
SearchOperation operation
) throws Exception {
boolean debug = log.isDebugEnabled();
DN dn = operation.getDn();
Collection<String> requestedAttributes = operation.getAttributes();
if (debug) {
log.debug("Normalized base DN: "+dn);
log.debug("Normalized attributes: "+requestedAttributes);
}
List<Entry> entries;
try {
entries = findEntries(dn);
} catch (Exception e) {
operation.close();
throw e;
}
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
operation.close();
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
searchEntries(operation, entries, true);
}
public void searchEntry(
final SearchOperation operation,
final Entry entry
) throws Exception {
boolean debug = log.isDebugEnabled();
SearchOperation op = new PipelineSearchOperation(operation) {
public void add(SearchResult result) throws Exception {
//if (debug) log.debug("Result: \""+result.getDn()+"\".");
super.add(result);
}
public void add(SearchReference reference) throws Exception {
//if (debug) log.debug("Reference: \""+ reference.getDn()+"\".");
super.add(reference);
}
public void close() throws Exception {
//if (debug) log.debug("Done.");
//super.close();
}
};
Collection<Module> modules = findModules(entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.search(op);
DN baseDn = op.getDn();
int scope = op.getScope();
if (scope == SearchRequest.SCOPE_BASE || scope == SearchRequest.SCOPE_ONE && entry.getParentDn().matches(baseDn)) {
if (debug) log.debug("Children of "+entry.getDn()+" are out of scope.");
return;
}
List<Entry> children = entry.getChildren();
if (children.size() == 0) {
if (debug) log.debug("Entry "+entry.getDn()+" has no children.");
return;
}
if (debug) log.debug("Searching children of "+entry.getDn()+".");
searchEntries(op, children, true);
}
public void searchEntries(
final SearchOperation operation,
final List<Entry> entries,
boolean wait
) throws Exception {
boolean debug = log.isDebugEnabled();
final ParallelSearchOperation op = new ParallelSearchOperation(operation, entries.size());
if (threadManager == null) {
// important for deterministic merging
if (debug) log.debug("Searching "+entries.size()+" entries sequentially.");
} else {
// could affect merging outcome
if (debug) log.debug("Searching "+entries.size()+" entries in parallel.");
}
for (final Entry entry : entries) {
if (debug) log.debug("Searching \""+entry.getDn()+"\" ("+entry.getName()+").");
if (op.isAbandoned()) {
if (debug) log.debug("Operation "+op.getOperationName()+" has been abandoned.");
op.close();
continue;
}
Runnable runnable = new Runnable() {
public void run() {
try {
searchEntry(op, entry);
} catch (LDAPException e) {
op.setException(e);
} catch (Throwable e) {
Penrose.errorLog.error(e.getMessage(), e);
op.setException(LDAP.createException(e));
} finally {
try { op.close(entry); } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); }
}
}
};
if (threadManager == null) {
runnable.run();
} else {
threadManager.execute(runnable);
}
}
if (wait) {
if (debug) log.debug("Waiting for "+entries.size()+" entries.");
op.waitFor();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Unbind
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void unbind(
Session session,
UnbindRequest request,
UnbindResponse response
) throws Exception {
boolean debug = log.isDebugEnabled();
try {
DN dn = session.getBindDn();
if (dn == null || dn.isEmpty()) return;
Collection<Entry> entries = findEntries(dn);
if (entries.isEmpty()) {
if (debug) log.debug("Entry "+dn+" not found.");
throw LDAP.createException(LDAP.NO_SUCH_OBJECT);
}
Collection<Module> modules = findModules(dn);
Exception exception = null;
for (Entry entry : entries) {
try {
if (debug) log.debug("Unbinding " + dn + " from " + entry.getDn());
ModuleChain chain = createModuleChain(entry, modules);
chain.unbind(session, request, response);
return; // return after the first successful operation
} catch (Exception e) {
exception = e;
}
}
throw exception;
} catch (LDAPException e) {
response.setException(e);
throw e;
}
}
public ACLEvaluator getAclEvaluator() {
return aclEvaluator;
}
public void setAclEvaluator(ACLEvaluator aclEvaluator) {
this.aclEvaluator = aclEvaluator;
}
public Interpreter newInterpreter() throws Exception {
ClassLoader classLoader = partitionContext.getClassLoader();
Interpreter interpreter = new DefaultInterpreter();
interpreter.setClassLoader(classLoader);
return interpreter;
}
public AdapterManager getAdapterManager() {
return adapterManager;
}
public void setAdapterManager(AdapterManager adapterManager) {
this.adapterManager = adapterManager;
}
public SchemaManager getSchemaManager() {
return schemaManager;
}
public void setSchemaManager(SchemaManager schemaManager) {
this.schemaManager = schemaManager;
}
public ThreadManager getThreadManager() {
return threadManager;
}
public void setThreadManager(ThreadManager threadManager) {
this.threadManager = threadManager;
}
public Collection<String> getDepends() {
return partitionConfig.getDepends();
}
}