From 95df5cfdba474acb03076953e992b898fbb277a8 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 02 Feb 2009 23:37:54 +0000
Subject: [PATCH] Fix issue 3734 - Make network group policies extensible.
---
opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java | 2777 +++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 1,757 insertions(+), 1,020 deletions(-)
diff --git a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
index 9afa115..60c1f11 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/NetworkGroup.java
@@ -26,177 +26,1375 @@
*/
package org.opends.server.core.networkgroups;
-import org.opends.messages.Message;
+
+
+import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.CoreMessages.*;
-import static org.opends.server.util.Validator.ensureNotNull;
+import static org.opends.server.loggers.ErrorLogger.*;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.Validator.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeMap;
import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
-import org.opends.server.admin.std.meta.
- NetworkGroupResourceLimitsCfgDefn.ReferralBindPolicy;
-import org.opends.server.admin.std.meta.
- NetworkGroupResourceLimitsCfgDefn.ReferralPolicy;
+import org.opends.messages.Message;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.std.meta.QOSPolicyCfgDefn;
+import org.opends.server.admin.std.server.NetworkGroupCfg;
+import org.opends.server.admin.std.server.QOSPolicyCfg;
import org.opends.server.api.ClientConnection;
-import org.opends.server.core.*;
+import org.opends.server.api.QOSPolicy;
+import org.opends.server.api.QOSPolicyFactory;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.RootDseWorkflowTopology;
+import org.opends.server.core.Workflow;
+import org.opends.server.core.WorkflowImpl;
+import org.opends.server.core.WorkflowTopologyNode;
+import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.types.AuthenticationType;
+import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
+import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
+import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import org.opends.server.types.operation.PreParseOperation;
import org.opends.server.workflowelement.WorkflowElement;
+
+
/**
- * This class defines the network group. A network group is used to categorize
- * client connections. A network group is defined by a set of criteria, a
- * set of policies and a set of workflow nodes. A client connection belongs to
- * a network group whenever it satisfies all the network group criteria. As
- * soon as a client connection belongs to a network group, it has to comply
- * with all the network group policies. Any cleared client operation can be
- * routed to one the network group workflow nodes.
+ * This class defines the network group. A network group is used to
+ * categorize client connections. A network group is defined by a set of
+ * criteria, a set of policies and a set of workflow nodes. A client
+ * connection belongs to a network group whenever it satisfies all the
+ * network group criteria. As soon as a client connection belongs to a
+ * network group, it has to comply with all the network group policies.
+ * Any cleared client operation can be routed to one the network group
+ * workflow nodes.
*/
public class NetworkGroup
{
- // Workflow nodes registered with the current network group.
- // Keys are workflowIDs.
- private TreeMap<String, WorkflowTopologyNode> registeredWorkflowNodes =
- new TreeMap<String, WorkflowTopologyNode>();
+ /**
+ * Configuration change listener for user network groups.
+ */
+ private final class ChangeListener implements
+ ConfigurationChangeListener<NetworkGroupCfg>
+ {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ NetworkGroupCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ List<Message> messages = new ArrayList<Message>();
+
+ // Update the priority.
+ setNetworkGroupPriority(configuration.getPriority());
+
+ // Deregister any workflows that have been removed.
+ SortedSet<String> configWorkflows = configuration.getWorkflow();
+ for (String id : getRegisteredWorkflows())
+ {
+ if (!configWorkflows.contains(id))
+ {
+ deregisterWorkflow(id);
+ }
+ }
+
+ // Register any workflows that have been added.
+ List<String> ngWorkflows = getRegisteredWorkflows();
+ for (String id : configuration.getWorkflow())
+ {
+ if (!ngWorkflows.contains(id))
+ {
+ WorkflowImpl workflowImpl =
+ (WorkflowImpl) WorkflowImpl.getWorkflow(id);
+ try
+ {
+ registerWorkflow(workflowImpl);
+ }
+ catch (DirectoryException e)
+ {
+ if (resultCode == ResultCode.SUCCESS)
+ {
+ resultCode = e.getResultCode();
+ }
+ messages.add(e.getMessageObject());
+ }
+ }
+ }
+
+ try
+ {
+ criteria = decodeConnectionCriteriaConfiguration(configuration);
+ }
+ catch (ConfigException e)
+ {
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ messages.add(e.getMessageObject());
+ }
+
+ // Update the configuration.
+ NetworkGroup.this.configuration = configuration;
+
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
- // A lock to protect concurrent access to the registered Workflow nodes.
- private Object registeredWorkflowNodesLock = new Object();
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(
+ NetworkGroupCfg configuration, List<Message> unacceptableReasons)
+ {
+ return isConfigurationAcceptable(configuration,
+ unacceptableReasons);
+ }
+
+ }
+
+ /**
+ * Configuration change listener for user network group QOS policies.
+ */
+ private final class QOSPolicyListener implements
+ ConfigurationAddListener<QOSPolicyCfg>,
+ ConfigurationDeleteListener<QOSPolicyCfg>
+ {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(
+ QOSPolicyCfg configuration)
+ {
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ List<Message> messages = new ArrayList<Message>();
+
+ try
+ {
+ createNetworkGroupQOSPolicy(configuration);
+ }
+ catch (ConfigException e)
+ {
+ messages.add(e.getMessageObject());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ catch (InitializationException e)
+ {
+ messages.add(e.getMessageObject());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired,
+ messages);
+ }
- // The workflow node for the rootDSE entry. The RootDSE workflow node
- // is not stored in the list of registered workflow nodes.
- private RootDseWorkflowTopology rootDSEWorkflowNode = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(
+ QOSPolicyCfg configuration)
+ {
+ QOSPolicy policy = policies.remove(configuration.dn());
+
+ if (policy != null)
+ {
+ if (requestFilteringPolicy == policy)
+ {
+ requestFilteringPolicy = null;
+ }
+ else if (resourceLimitsPolicy == policy)
+ {
+ resourceLimitsPolicy = null;
+ }
+
+ policy.finalizeQOSPolicy();
+ }
+
+ return new ConfigChangeResult(ResultCode.SUCCESS, false);
+ }
- // List of naming contexts handled by the network group.
- private NetworkGroupNamingContexts namingContexts =
- new NetworkGroupNamingContexts();
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(
+ QOSPolicyCfg configuration, List<Message> unacceptableReasons)
+ {
+ return isNetworkGroupQOSPolicyConfigurationAcceptable(
+ configuration, unacceptableReasons);
+ }
- // The default network group (singleton).
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(
+ QOSPolicyCfg configuration, List<Message> unacceptableReasons)
+ {
+ // Always ok.
+ return true;
+ }
+
+ }
+
+
+
+ // The admin network group has no criterion, no policy,
+ // and gives access to all the workflows.
+ private static final String ADMIN_NETWORK_GROUP_NAME = "admin";
+
+ private static NetworkGroup adminNetworkGroup =
+ new NetworkGroup(ADMIN_NETWORK_GROUP_NAME);
+
// The default network group has no criterion, no policy, and gives
// access to all the workflows. The purpose of the default network
// group is to allow new clients to perform a first operation before
// they can be attached to a specific network group.
private static final String DEFAULT_NETWORK_GROUP_NAME = "default";
- private final boolean isDefaultNetworkGroup;
+
private static NetworkGroup defaultNetworkGroup =
- new NetworkGroup (DEFAULT_NETWORK_GROUP_NAME);
+ new NetworkGroup(DEFAULT_NETWORK_GROUP_NAME);
-
- // The admin network group (singleton).
- // The admin network group has no criterion, no policy, and gives
- // access to all the workflows.
- private static final String ADMIN_NETWORK_GROUP_NAME = "admin";
- private final boolean isAdminNetworkGroup;
- private static NetworkGroup adminNetworkGroup =
- new NetworkGroup (ADMIN_NETWORK_GROUP_NAME);
-
-
- // The internal network group (singleton).
// The internal network group has no criterion, no policy, and gives
// access to all the workflows. The purpose of the internal network
// group is to allow internal connections to perform operations.
private static final String INTERNAL_NETWORK_GROUP_NAME = "internal";
- private boolean isInternalNetworkGroup;
private static NetworkGroup internalNetworkGroup =
new NetworkGroup(INTERNAL_NETWORK_GROUP_NAME);
+ // The ordered list of network groups.
+ private static List<NetworkGroup> orderedNetworkGroups =
+ new ArrayList<NetworkGroup>();
// The list of all network groups that are registered with the server.
- // The defaultNetworkGroup is not in the list of registered network groups.
+ // The defaultNetworkGroup is not in the list of registered network
+ // groups.
private static TreeMap<String, NetworkGroup> registeredNetworkGroups =
new TreeMap<String, NetworkGroup>();
// A lock to protect concurrent access to the registeredNetworkGroups.
private static Object registeredNetworkGroupsLock = new Object();
- // The ordered list of network groups.
- private static List<NetworkGroup> orderedNetworkGroups =
- new ArrayList<NetworkGroup>();
+ /**
+ * The tracer object for the debug logger.
+ */
+ private static final DebugTracer TRACER = getTracer();
- // The network group internal identifier.
- private String networkGroupID = null;
-
- // The network group priority
- private int priority = 100;
-
- // The network group criteria.
- private NetworkGroupCriteria criteria = null;
-
- // The network group resource limits
- private ResourceLimits resourceLimits = null;
-
- // The network group request filtering policy
- private RequestFilteringPolicy requestFilteringPolicy = null;
-
- // The statistics
- private NetworkGroupStatistics stats;
-
- // The client connection affinity policy.
- private ClientConnectionAffinityPolicy affinityPolicy =
- ClientConnectionAffinityPolicy.NONE;
-
- // The client connection affinity timeout (number of seconds).
- private long affinityTimeout = 0;
-
/**
- * Creates a new instance of the network group.
- *
- * @param networkGroupID the network group internal identifier
+ * Deregisters all network groups that have been registered. This
+ * should be called when the server is shutting down.
*/
- public NetworkGroup(
- String networkGroupID
- )
+ public static void deregisterAllOnShutdown()
+ {
+ synchronized (registeredNetworkGroupsLock)
+ {
+ // Invalidate all NetworkGroups so they cannot accidentally be
+ // used after a restart.
+ Collection<NetworkGroup> networkGroups =
+ registeredNetworkGroups.values();
+ for (NetworkGroup networkGroup : networkGroups)
+ {
+ networkGroup.invalidate();
+ }
+ defaultNetworkGroup.invalidate();
+ adminNetworkGroup.invalidate();
+ internalNetworkGroup.invalidate();
+
+ registeredNetworkGroups = new TreeMap<String, NetworkGroup>();
+ orderedNetworkGroups = new ArrayList<NetworkGroup>();
+ defaultNetworkGroup = new NetworkGroup("default");
+ adminNetworkGroup = new NetworkGroup("admin");
+ internalNetworkGroup = new NetworkGroup("internal");
+ }
+ }
+
+
+
+ /**
+ * Gets the highest priority matching network group for a BIND op.
+ *
+ * @param connection
+ * the client connection
+ * @param dn
+ * the operation bindDN
+ * @param authType
+ * the operation authentication type
+ * @param isSecure
+ * a boolean indicating whether the operation is secured
+ * @return matching network group
+ */
+ static NetworkGroup findBindMatchingNetworkGroup(
+ ClientConnection connection, DN dn, AuthenticationType authType,
+ boolean isSecure)
+ {
+ for (NetworkGroup ng : orderedNetworkGroups)
+ {
+ if (ng.matchAfterBind(connection, dn, authType, isSecure))
+ {
+ return ng;
+ }
+ }
+ return defaultNetworkGroup;
+ }
+
+
+
+ /**
+ * Gets the highest priority matching network group.
+ *
+ * @param connection
+ * the client connection
+ * @return matching network group
+ */
+ static NetworkGroup findMatchingNetworkGroup(
+ ClientConnection connection)
+ {
+ for (NetworkGroup ng : orderedNetworkGroups)
+ {
+ if (ng.match(connection))
+ {
+ return ng;
+ }
+ }
+ return defaultNetworkGroup;
+ }
+
+
+
+ /**
+ * Returns the admin network group.
+ *
+ * @return the admin network group
+ */
+ public static NetworkGroup getAdminNetworkGroup()
+ {
+ return adminNetworkGroup;
+ }
+
+
+
+ /**
+ * Returns the default network group. The default network group is
+ * always defined and has no criterion, no policy and provide full
+ * access to all the registered workflows.
+ *
+ * @return the default network group
+ */
+ public static NetworkGroup getDefaultNetworkGroup()
+ {
+ return defaultNetworkGroup;
+ }
+
+
+
+ /**
+ * Returns the internal network group.
+ *
+ * @return the internal network group
+ */
+ public static NetworkGroup getInternalNetworkGroup()
+ {
+ return internalNetworkGroup;
+ }
+
+
+
+ /**
+ * Gets the network group having the specified ID.
+ * <p>
+ * This method is for testing only.
+ *
+ * @param networkGroupID
+ * The network group ID.
+ * @return The network group, of <code>null</code> if no match was found.
+ */
+ public static NetworkGroup getNetworkGroup(String networkGroupID)
+ {
+ return registeredNetworkGroups.get(networkGroupID);
+ }
+
+
+
+ /**
+ * Resets the configuration of all the registered network groups.
+ */
+ public static void resetConfig()
+ {
+ // Reset the default network group
+ defaultNetworkGroup.reset();
+ adminNetworkGroup.reset();
+ internalNetworkGroup.reset();
+
+ // Reset all the registered network group
+ synchronized (registeredNetworkGroupsLock)
+ {
+ registeredNetworkGroups = new TreeMap<String, NetworkGroup>();
+ orderedNetworkGroups = new ArrayList<NetworkGroup>();
+ }
+ }
+
+
+
+ /**
+ * Initializes this network group as a user network group using the
+ * provided configuration. The network group will monitor the
+ * configuration and update its configuration when necessary.
+ *
+ * @param configuration
+ * The network group configuration.
+ * @return The new user network group.
+ * @throws ConfigException
+ * If an unrecoverable problem arises during initialization
+ * of the user network group as a result of the server
+ * configuration.
+ * @throws InitializationException
+ * If a problem occurs during initialization of the user
+ * network group that is not related to the server
+ * configuration.
+ */
+ static NetworkGroup createUserNetworkGroup(
+ NetworkGroupCfg configuration) throws InitializationException,
+ ConfigException
+ {
+ NetworkGroup networkGroup = new NetworkGroup(configuration);
+
+ try
+ {
+ // Set the priority.
+ networkGroup.priority = configuration.getPriority();
+
+ // Initialize the network group criteria.
+ networkGroup.criteria =
+ decodeConnectionCriteriaConfiguration(configuration);
+
+ // Initialize the network group policies.
+ for (String policyName : configuration
+ .listNetworkGroupQOSPolicies())
+ {
+ QOSPolicyCfg policyConfiguration =
+ configuration.getNetworkGroupQOSPolicy(policyName);
+ networkGroup.createNetworkGroupQOSPolicy(policyConfiguration);
+ }
+
+ // Register the root DSE workflow with the network group.
+ WorkflowImpl rootDSEworkflow =
+ (WorkflowImpl) WorkflowImpl.getWorkflow("__root.dse__#");
+ networkGroup.registerWorkflow(rootDSEworkflow);
+
+ // Register the workflows with the network group.
+ for (String workflowID : configuration.getWorkflow())
+ {
+ WorkflowImpl workflowImpl =
+ (WorkflowImpl) WorkflowImpl.getWorkflow(workflowID);
+
+ if (workflowImpl == null)
+ {
+ // The workflow does not exist, log an error message
+ // and skip the workflow.
+ Message message =
+ INFO_ERR_WORKFLOW_DOES_NOT_EXIST.get(workflowID,
+ networkGroup.getID());
+ logError(message);
+ }
+ else
+ {
+ networkGroup.registerWorkflow(workflowImpl);
+ }
+ }
+
+ // Register all configuration change listeners.
+ configuration.addChangeListener(networkGroup.changeListener);
+ configuration
+ .addNetworkGroupQOSPolicyAddListener(networkGroup.policyListener);
+ configuration
+ .addNetworkGroupQOSPolicyDeleteListener(networkGroup.policyListener);
+
+ // Register the network group with the server.
+ networkGroup.register();
+ }
+ catch (DirectoryException e)
+ {
+ networkGroup.finalizeNetworkGroup();
+ throw new InitializationException(e.getMessageObject());
+ }
+ catch (InitializationException e)
+ {
+ networkGroup.finalizeNetworkGroup();
+ throw e;
+ }
+ catch (ConfigException e)
+ {
+ networkGroup.finalizeNetworkGroup();
+ throw e;
+ }
+
+ return networkGroup;
+ }
+
+
+
+ /**
+ * Indicates whether the provided network group configuration is
+ * acceptable.
+ *
+ * @param configuration
+ * The network group configuration.
+ * @param unacceptableReasons
+ * A list that can be used to hold messages about why the
+ * provided configuration is not acceptable.
+ * @return Returns <code>true</code> if the provided network group
+ * configuration is acceptable, or <code>false</code> if it is
+ * not.
+ */
+ static boolean isConfigurationAcceptable(
+ NetworkGroupCfg configuration, List<Message> unacceptableReasons)
+ {
+ // The configuration is always acceptable if disabled.
+ if (!configuration.isEnabled())
+ {
+ return true;
+ }
+
+ // Check that all the workflows in the network group have a
+ // different base DN.
+ boolean isAcceptable = true;
+
+ Set<String> allBaseDNs = new HashSet<String>();
+ for (String workflowId : configuration.getWorkflow())
+ {
+ WorkflowImpl workflow =
+ (WorkflowImpl) WorkflowImpl.getWorkflow(workflowId);
+ String baseDN = workflow.getBaseDN().toNormalizedString();
+ if (allBaseDNs.contains(baseDN))
+ {
+ // This baseDN is duplicated
+ Message message =
+ ERR_WORKFLOW_BASE_DN_DUPLICATED_IN_NG.get(baseDN,
+ getNameFromConfiguration(configuration));
+ unacceptableReasons.add(message);
+ isAcceptable = false;
+ break;
+ }
+ else
+ {
+ allBaseDNs.add(baseDN);
+ }
+ }
+
+ // Validate any policy configurations.
+ for (String policyName : configuration
+ .listNetworkGroupQOSPolicies())
+ {
+ try
+ {
+ QOSPolicyCfg policyCfg =
+ configuration.getNetworkGroupQOSPolicy(policyName);
+ if (!isNetworkGroupQOSPolicyConfigurationAcceptable(policyCfg,
+ unacceptableReasons))
+ {
+ isAcceptable = false;
+ }
+ }
+ catch (ConfigException e)
+ {
+ // This is bad - give up immediately.
+ unacceptableReasons.add(e.getMessageObject());
+ return false;
+ }
+ }
+
+ // The bind DN patterns may be malformed.
+ if (!configuration.getAllowedBindDN().isEmpty())
+ {
+ try
+ {
+ BindDNConnectionCriteria.decode(configuration
+ .getAllowedBindDN());
+ }
+ catch (DirectoryException e)
+ {
+ unacceptableReasons.add(e.getMessageObject());
+ isAcceptable = false;
+ }
+ }
+
+ return isAcceptable;
+ }
+
+
+
+ // Decodes connection criteria configuration.
+ private static ConnectionCriteria decodeConnectionCriteriaConfiguration(
+ NetworkGroupCfg configuration) throws ConfigException
+ {
+ List<ConnectionCriteria> filters =
+ new LinkedList<ConnectionCriteria>();
+
+ if (!configuration.getAllowedAuthMethod().isEmpty())
+ {
+ filters.add(new AuthMethodConnectionCriteria(configuration
+ .getAllowedAuthMethod()));
+ }
+
+ if (!configuration.getAllowedBindDN().isEmpty())
+ {
+ try
+ {
+ filters.add(BindDNConnectionCriteria.decode(configuration
+ .getAllowedBindDN()));
+ }
+ catch (DirectoryException e)
+ {
+ throw new ConfigException(e.getMessageObject());
+ }
+ }
+
+ if (!configuration.getAllowedClient().isEmpty()
+ || !configuration.getDeniedClient().isEmpty())
+ {
+ filters.add(new IPConnectionCriteria(configuration
+ .getAllowedClient(), configuration.getDeniedClient()));
+ }
+
+ if (!configuration.getAllowedProtocol().isEmpty())
+ {
+ filters.add(new ProtocolConnectionCriteria(configuration
+ .getAllowedProtocol()));
+ }
+
+ if (configuration.isIsSecurityMandatory())
+ {
+ filters.add(SecurityConnectionCriteria.SECURITY_REQUIRED);
+ }
+
+ if (filters.isEmpty())
+ {
+ return ConnectionCriteria.TRUE;
+ }
+ else
+ {
+ return new ANDConnectionCriteria(filters);
+ }
+ }
+
+
+
+ /**
+ * Gets the name of the network group configuration.
+ *
+ * @param configuration
+ * The configuration.
+ * @return The network group name.
+ */
+ private static String getNameFromConfiguration(NetworkGroupCfg configuration)
+ {
+ DN dn = configuration.dn();
+ return dn.getRDN().getAttributeValue(0).getStringValue();
+ }
+
+
+
+ // Determines whether or not the new network group configuration's
+ // implementation class is acceptable.
+ private static boolean isNetworkGroupQOSPolicyConfigurationAcceptable(
+ QOSPolicyCfg policyConfiguration,
+ List<Message> unacceptableReasons)
+ {
+ String className = policyConfiguration.getJavaClass();
+ QOSPolicyCfgDefn d = QOSPolicyCfgDefn.getInstance();
+ ClassPropertyDefinition pd = d.getJavaClassPropertyDefinition();
+
+ // Validate the configuration.
+ try
+ {
+ // Load the class and cast it to a network group policy factory.
+ Class<? extends QOSPolicyFactory> theClass;
+ QOSPolicyFactory factory;
+
+ theClass = pd.loadClass(className, QOSPolicyFactory.class);
+ factory = theClass.newInstance();
+
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ Method method =
+ theClass.getMethod("isConfigurationAcceptable",
+ QOSPolicyCfg.class, List.class);
+ Boolean acceptable =
+ (Boolean) method.invoke(factory, policyConfiguration,
+ unacceptableReasons);
+
+ if (!acceptable)
+ {
+ return false;
+ }
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ unacceptableReasons
+ .add(ERR_CONFIG_NETWORK_GROUP_POLICY_CANNOT_INITIALIZE.get(
+ String.valueOf(className), String
+ .valueOf(policyConfiguration.dn()),
+ stackTraceToSingleLineString(e)));
+ return false;
+ }
+
+ // The configuration is valid as far as we can tell.
+ return true;
+ }
+
+
+
+ // Change listener (active for user network groups).
+ private final ChangeListener changeListener;
+
+ // Current configuration (active for user network groups).
+ private NetworkGroupCfg configuration = null;
+
+ // The network group connection criteria.
+ private ConnectionCriteria criteria = ConnectionCriteria.TRUE;
+
+ private final boolean isAdminNetworkGroup;
+
+ private final boolean isDefaultNetworkGroup;
+
+ private final boolean isInternalNetworkGroup;
+
+ // List of naming contexts handled by the network group.
+ private NetworkGroupNamingContexts namingContexts =
+ new NetworkGroupNamingContexts();
+
+ // The network group internal identifier.
+ private final String networkGroupID;
+
+ // All network group policies mapping factory class name to policy.
+ private final Map<DN, QOSPolicy> policies =
+ new ConcurrentHashMap<DN, QOSPolicy>();
+
+ // Add/delete policy listener (active for user network groups).
+ private final QOSPolicyListener policyListener;
+
+ // The network group priority.
+ private int priority = 100;
+
+ // Workflow nodes registered with the current network group.
+ // Keys are workflowIDs.
+ private TreeMap<String, WorkflowTopologyNode> registeredWorkflowNodes =
+ new TreeMap<String, WorkflowTopologyNode>();
+
+ // A lock to protect concurrent access to the registered Workflow
+ // nodes.
+ private final Object registeredWorkflowNodesLock = new Object();
+
+ // The network group request filtering policy.
+ private RequestFilteringPolicy requestFilteringPolicy = null;
+
+ // The network group resource limits policy.
+ private ResourceLimitsPolicy resourceLimitsPolicy = null;
+
+ // The workflow node for the rootDSE entry. The RootDSE workflow node
+ // is not stored in the list of registered workflow nodes.
+ private RootDseWorkflowTopology rootDSEWorkflowNode = null;
+
+ // The network group statistics.
+ private final NetworkGroupStatistics statistics;
+
+
+
+ /**
+ * Creates a new system network group using the provided ID.
+ *
+ * @param networkGroupID
+ * The network group internal identifier.
+ */
+ public NetworkGroup(String networkGroupID)
{
this.networkGroupID = networkGroupID;
-
- isInternalNetworkGroup = INTERNAL_NETWORK_GROUP_NAME.equals(networkGroupID);
- isAdminNetworkGroup = ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
- isDefaultNetworkGroup = DEFAULT_NETWORK_GROUP_NAME.equals(networkGroupID);
-
- stats = new NetworkGroupStatistics(this);
+ this.isInternalNetworkGroup =
+ INTERNAL_NETWORK_GROUP_NAME.equals(networkGroupID);
+ this.isAdminNetworkGroup =
+ ADMIN_NETWORK_GROUP_NAME.equals(networkGroupID);
+ this.isDefaultNetworkGroup =
+ DEFAULT_NETWORK_GROUP_NAME.equals(networkGroupID);
+ this.statistics = new NetworkGroupStatistics(this);
+ this.configuration = null;
+ this.changeListener = null;
+ this.policyListener = null;
}
+
+ /**
+ * Creates a new user network group using the provided configuration.
+ */
+ private NetworkGroup(NetworkGroupCfg configuration)
+ {
+ this.networkGroupID = getNameFromConfiguration(configuration);
+ this.isInternalNetworkGroup = false;
+ this.isAdminNetworkGroup = false;
+ this.isDefaultNetworkGroup = false;
+ this.statistics = new NetworkGroupStatistics(this);
+ this.configuration = configuration;
+ this.changeListener = new ChangeListener();
+ this.policyListener = new QOSPolicyListener();
+ }
+
+
+
+ /**
+ * Adds a connection to the group.
+ *
+ * @param connection
+ * the ClientConnection
+ */
+ public void addConnection(ClientConnection connection)
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ resourceLimitsPolicy.addConnection(connection);
+ }
+ }
+
+
+
+ /**
+ * Checks the request filtering policy.
+ *
+ * @param operation
+ * the operation to be checked
+ * @param messages
+ * the error messages
+ * @return boolean indicating whether the operation conforms to the
+ * network group request filtering policy
+ */
+ boolean checkRequestFilteringPolicy(
+ PreParseOperation operation, List<Message> messages)
+ {
+ if (requestFilteringPolicy != null)
+ {
+ return requestFilteringPolicy.isAllowed(operation, messages);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Checks the resource limits policy.
+ *
+ * @param connection
+ * the client connection
+ * @param operation
+ * the ongoing operation
+ * @param fullCheck
+ * a boolean indicating the level of checking: full/partial
+ * @param messages
+ * the messages indicating the cause of the failure.
+ * @return a boolean indicating whether resource limits are exceeded
+ */
+ boolean checkResourceLimitsPolicy(ClientConnection connection,
+ PreParseOperation operation, boolean fullCheck,
+ List<Message> messages)
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ return resourceLimitsPolicy.isAllowed(connection, operation,
+ fullCheck, messages);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Deregisters a workflow with the network group. The workflow to
+ * deregister is identified by its baseDN.
+ *
+ * @param baseDN
+ * the baseDN of the workflow to deregister, may be null
+ * @return the deregistered workflow
+ */
+ public Workflow deregisterWorkflow(DN baseDN)
+ {
+ Workflow workflow = null;
+
+ if (baseDN == null)
+ {
+ return workflow;
+ }
+
+ if (baseDN.isNullDN())
+ {
+ // deregister the rootDSE
+ deregisterWorkflow(rootDSEWorkflowNode);
+ workflow = rootDSEWorkflowNode.getWorkflowImpl();
+ }
+ else
+ {
+ // deregister a workflow node
+ synchronized (registeredWorkflowNodesLock)
+ {
+ for (WorkflowTopologyNode node : registeredWorkflowNodes
+ .values())
+ {
+ DN curDN = node.getBaseDN();
+ if (curDN.equals(baseDN))
+ {
+ // Call deregisterWorkflow() instead of
+ // deregisterWorkflowNode() because we want the naming
+ // context list to be updated as well.
+ deregisterWorkflow(node);
+ workflow = node.getWorkflowImpl();
+
+ // Only one workflow can match the baseDN, so we can break
+ // the loop here.
+ break;
+ }
+ }
+ }
+ }
+
+ // Now that the workflow node has been deregistered with the network
+ // group, update the reference counter of the workflow.
+ if ((workflow != null) && !isAdminNetworkGroup
+ && !isInternalNetworkGroup && !isDefaultNetworkGroup)
+ {
+ WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
+ workflowImpl.decrementReferenceCounter();
+ }
+
+ return workflow;
+ }
+
+
+
+ /**
+ * Deregisters a workflow with the network group. The workflow to
+ * deregister is identified by its workflow ID.
+ *
+ * @param workflowID
+ * the workflow identifier of the workflow to deregister
+ * @return the deregistered workflow
+ */
+ public Workflow deregisterWorkflow(String workflowID)
+ {
+ Workflow workflow = null;
+
+ String rootDSEWorkflowID = null;
+ if (rootDSEWorkflowNode != null)
+ {
+ rootDSEWorkflowID =
+ rootDSEWorkflowNode.getWorkflowImpl().getWorkflowId();
+ }
+
+ if (workflowID.equalsIgnoreCase(rootDSEWorkflowID))
+ {
+ // deregister the rootDSE
+ deregisterWorkflow(rootDSEWorkflowNode);
+ workflow = rootDSEWorkflowNode.getWorkflowImpl();
+ }
+ else
+ {
+ // deregister a workflow node
+ synchronized (registeredWorkflowNodesLock)
+ {
+ for (WorkflowTopologyNode node : registeredWorkflowNodes
+ .values())
+ {
+ String curID = node.getWorkflowImpl().getWorkflowId();
+ if (curID.equals(workflowID))
+ {
+ // Call deregisterWorkflow() instead of
+ // deregisterWorkflowNode() because we want the naming
+ // context list to be updated as well.
+ deregisterWorkflow(node);
+ workflow = node.getWorkflowImpl();
+
+ // Only one workflow can match the baseDN, so we can break
+ // the loop here.
+ break;
+ }
+ }
+ }
+ }
+
+ // Now that the workflow node has been deregistered with the network
+ // group, update the reference counter of the workflow.
+ if ((workflow != null) && !isAdminNetworkGroup
+ && !isInternalNetworkGroup && !isDefaultNetworkGroup)
+ {
+ WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
+ workflowImpl.decrementReferenceCounter();
+ }
+
+ return workflow;
+ }
+
+
+
+ /**
+ * Performs any finalization that might be required when this network
+ * group is unloaded. No action is taken in the default
+ * implementation.
+ */
+ public void finalizeNetworkGroup()
+ {
+ if (configuration != null)
+ {
+ // Finalization specific to user network groups.
+ deregister();
+
+ // Remove all change listeners.
+ configuration.removeChangeListener(changeListener);
+ configuration
+ .removeNetworkGroupQOSPolicyAddListener(policyListener);
+ configuration
+ .removeNetworkGroupQOSPolicyDeleteListener(policyListener);
+
+ configuration = null;
+ }
+
+ // Clean up policies.
+ for (QOSPolicy policy : policies.values())
+ {
+ policy.finalizeQOSPolicy();
+ }
+
+ requestFilteringPolicy = null;
+ resourceLimitsPolicy = null;
+ criteria = ConnectionCriteria.TRUE;
+ policies.clear();
+ }
+
+
+
/**
* Retrieves the network group ID.
+ *
* @return a string indicating the network group ID
*/
- public String getID() {
+ public String getID()
+ {
return networkGroupID;
}
+
/**
- * Performs any finalization that might be required when this
- * network group is unloaded. No action is taken in the
- * default implementation.
+ * Gets the minimum string length of a substring filter in a search
+ * operation.
+ *
+ * @return the minimum substring length
*/
- public void finalizeNetworkGroup()
+ public int getMinSubstring()
{
- // No action is required by default.
+ if (resourceLimitsPolicy != null)
+ {
+ return resourceLimitsPolicy.getMinSubstring();
+ }
+ else
+ {
+ return 0;
+ }
}
+
+ /**
+ * Returns the list of naming contexts handled by the network group.
+ *
+ * @return the list of naming contexts
+ */
+ public NetworkGroupNamingContexts getNamingContexts()
+ {
+ return namingContexts;
+ }
+
+
+
+ /**
+ * Returns the QOS policy associated with this network group having
+ * the specified class.
+ *
+ * @param <T>
+ * The type of QOS policy.
+ * @param clazz
+ * The class of QOS policy requested.
+ * @return The QOS policy associated with this network group having
+ * the specified class, or <code>null</code> if none was
+ * found.
+ */
+ public <T extends QOSPolicy> T getNetworkGroupQOSPolicy(Class<T> clazz)
+ {
+ for (QOSPolicy policy : policies.values())
+ {
+ if (clazz.isAssignableFrom(policy.getClass()))
+ {
+ return clazz.cast(policy);
+ }
+ }
+
+ return null;
+ }
+
+
+
+ /**
+ * Gets the search size limit, i.e. the maximum number of entries
+ * returned by a search.
+ *
+ * @return the maximum number of entries returned by a search
+ */
+ public int getSizeLimit()
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ return resourceLimitsPolicy.getSizeLimit();
+ }
+ else
+ {
+ return DirectoryServer.getSizeLimit();
+ }
+ }
+
+
+
+ /**
+ * Gets the search duration limit, i.e. the maximum duration of a
+ * search operation.
+ *
+ * @return the maximum duration in ms of a search operation
+ */
+ public int getTimeLimit()
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ return resourceLimitsPolicy.getTimeLimit();
+ }
+ else
+ {
+ return DirectoryServer.getTimeLimit();
+ }
+ }
+
+
+
+ /**
+ * Gets the highest workflow in the topology that can handle the
+ * baseDN.
+ *
+ * @param baseDN
+ * the base DN of the request
+ * @return the highest workflow in the topology that can handle the
+ * base DN, <code>null</code> if none was found
+ */
+ public Workflow getWorkflowCandidate(DN baseDN)
+ {
+ // the top workflow to return
+ Workflow workflowCandidate = null;
+
+ // get the list of workflow candidates
+ if (baseDN.isNullDN())
+ {
+ // The rootDSE workflow is the candidate.
+ workflowCandidate = rootDSEWorkflowNode;
+ }
+ else
+ {
+ // Search the highest workflow in the topology that can handle
+ // the baseDN.
+ for (WorkflowTopologyNode curWorkflow : namingContexts
+ .getNamingContexts())
+ {
+ workflowCandidate = curWorkflow.getWorkflowCandidate(baseDN);
+ if (workflowCandidate != null)
+ {
+ break;
+ }
+ }
+ }
+
+ return workflowCandidate;
+ }
+
+
+
+ /**
+ * Registers a workflow with the network group.
+ *
+ * @param workflow
+ * the workflow to register
+ * @throws DirectoryException
+ * If the workflow ID for the provided workflow conflicts
+ * with the workflow ID of an existing workflow.
+ */
+ public void registerWorkflow(WorkflowImpl workflow)
+ throws DirectoryException
+ {
+ // The workflow is registered with no pre/post workflow element.
+ registerWorkflow(workflow, null, null);
+ }
+
+
+
+ /**
+ * Removes a connection from the group.
+ *
+ * @param connection
+ * the ClientConnection
+ */
+ public void removeConnection(ClientConnection connection)
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ resourceLimitsPolicy.removeConnection(connection);
+ }
+ }
+
+
+
+ /**
+ * Updates the operations statistics.
+ *
+ * @param message
+ * The LDAP message being processed
+ */
+ public void updateMessageRead(LDAPMessage message)
+ {
+ statistics.updateMessageRead(message);
+ }
+
+
+
+ /**
+ * Deregisters the current network group (this) with the server. The
+ * method also decrements the reference counter of the workflows so
+ * that workflows can be disabled or deleted if needed.
+ * <p>
+ * This methods is package private for testing purposes.
+ */
+ void deregister()
+ {
+ // Finalization specific to user network groups.
+ synchronized (registeredNetworkGroupsLock)
+ {
+ // Deregister this network group.
+ TreeMap<String, NetworkGroup> networkGroups =
+ new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
+ networkGroups.remove(networkGroupID);
+ registeredNetworkGroups = networkGroups;
+ orderedNetworkGroups.remove(this);
+
+ // Decrement the reference counter of the workflows registered
+ // with this network group.
+ synchronized (registeredWorkflowNodesLock)
+ {
+ for (WorkflowTopologyNode workflowNode : registeredWorkflowNodes
+ .values())
+ {
+ WorkflowImpl workflowImpl = workflowNode.getWorkflowImpl();
+ workflowImpl.decrementReferenceCounter();
+ }
+ }
+ }
+ }
+
+
+
+ /**
+ * Returns the request filtering policy statistics associated with
+ * this network group.
+ *
+ * @return The request filtering policy statistics associated with
+ * this network group.
+ */
+ RequestFilteringPolicyStatistics getRequestFilteringPolicyStatistics()
+ {
+ if (requestFilteringPolicy != null)
+ {
+ return requestFilteringPolicy.getStatistics();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+
+ /**
+ * Returns the resource limits policy statistics associated with this
+ * network group.
+ *
+ * @return The resource limits policy statistics associated with this
+ * network group.
+ */
+ ResourceLimitsPolicyStatistics getResourceLimitsPolicyStatistics()
+ {
+ if (resourceLimitsPolicy != null)
+ {
+ return resourceLimitsPolicy.getStatistics();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+
/**
* Registers the current network group (this) with the server.
+ * <p>
+ * This methods is package private for testing purposes.
*
- * @throws DirectoryException If the network group ID for the provided
- * network group conflicts with the network
- * group ID of an existing network group.
+ * @throws InitializationException
+ * If the network group ID for the provided network group
+ * conflicts with the network group ID of an existing
+ * network group.
*/
- public void register()
- throws DirectoryException
+ void register() throws InitializationException
{
ensureNotNull(networkGroupID);
@@ -205,24 +1403,28 @@
// The network group must not be already registered
if (registeredNetworkGroups.containsKey(networkGroupID))
{
- Message message = ERR_REGISTER_NETWORK_GROUP_ALREADY_EXISTS.get(
- networkGroupID);
- throw new DirectoryException(
- ResultCode.UNWILLING_TO_PERFORM, message);
+ Message message =
+ ERR_REGISTER_NETWORK_GROUP_ALREADY_EXISTS
+ .get(networkGroupID);
+ throw new InitializationException(message);
}
TreeMap<String, NetworkGroup> newRegisteredNetworkGroups =
- new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
+ new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
newRegisteredNetworkGroups.put(networkGroupID, this);
registeredNetworkGroups = newRegisteredNetworkGroups;
- // Insert the network group at the right position in the ordered list
+ // Insert the network group at the right position in the ordered
+ // list.
int index = 0;
- for (NetworkGroup ng : registeredNetworkGroups.values()) {
- if (ng.equals(this)) {
+ for (NetworkGroup ng : registeredNetworkGroups.values())
+ {
+ if (ng.equals(this))
+ {
continue;
}
- if (this.priority > ng.priority) {
+ if (this.priority > ng.priority)
+ {
index++;
}
}
@@ -231,103 +1433,474 @@
}
- /**
- * Deregisters the current network group (this) with the server.
- * The method also decrements the reference counter of the workflows
- * so that workflows can be disabled or deleted if needed.
- */
- public void deregister()
- {
- synchronized (registeredNetworkGroupsLock)
- {
- TreeMap<String, NetworkGroup> networkGroups =
- new TreeMap<String, NetworkGroup>(registeredNetworkGroups);
- networkGroups.remove(networkGroupID);
- registeredNetworkGroups = networkGroups;
- orderedNetworkGroups.remove(this);
- // decrement the reference counter of the workflows registered with
- // this network group
- updateWorkflowReferenceCounters();
- }
+ /**
+ * Sets the network group connection criteria.
+ * <p>
+ * This method is intended for testing only.
+ *
+ * @param criteria
+ * The connection criteria.
+ */
+ void setConnectionCriteria(ConnectionCriteria criteria)
+ {
+ this.criteria = criteria;
}
+
/**
- * Decrements the workflow reference counters of all the workflows
- * registered with this network group.
+ * Sets the network group priority.
+ * <p>
+ * This methods is package private for testing purposes.
+ *
+ * @param prio
+ * the network group priority
*/
- private void updateWorkflowReferenceCounters()
+ void setNetworkGroupPriority(int prio)
{
- synchronized (registeredWorkflowNodesLock)
+ // Check whether the priority has changed
+ if (priority != prio)
{
- for (WorkflowTopologyNode workflowNode: registeredWorkflowNodes.values())
+ synchronized (registeredNetworkGroupsLock)
{
- WorkflowImpl workflowImpl = workflowNode.getWorkflowImpl();
- workflowImpl.decrementReferenceCounter();
+ priority = prio;
+
+ // Nothing to do if the network group is not registered
+ if (registeredNetworkGroups.containsKey(networkGroupID))
+ {
+ // If the network group was already registered, remove it from
+ // the ordered list
+ orderedNetworkGroups.remove(this);
+
+ // Then insert it at the right position in the ordered list
+ int index = 0;
+ for (NetworkGroup ng : registeredNetworkGroups.values())
+ {
+ if (ng.equals(this))
+ {
+ continue;
+ }
+ if (this.priority > ng.priority)
+ {
+ index++;
+ }
+ }
+ orderedNetworkGroups.add(index, this);
+ }
}
}
}
+
/**
- * Registers a workflow with the network group.
+ * Dumps info from the current network group for debug purpose.
+ * <p>
+ * This method is intended for testing only.
*
- * @param workflow the workflow to register
- *
- * @throws DirectoryException If the workflow ID for the provided
- * workflow conflicts with the workflow
- * ID of an existing workflow.
+ * @param leftMargin
+ * white spaces used to indent traces
+ * @return a string buffer that contains trace information
*/
- public void registerWorkflow(
- WorkflowImpl workflow
- ) throws DirectoryException
+ StringBuilder toString(String leftMargin)
{
- // The workflow is registered with no pre/post workflow element.
- registerWorkflow(workflow, null, null);
+ StringBuilder sb = new StringBuilder();
+ String newMargin = leftMargin + " ";
+
+ sb.append(leftMargin + "Networkgroup (" + networkGroupID + "\n");
+ sb.append(leftMargin + "List of registered workflows:\n");
+ for (WorkflowTopologyNode node : registeredWorkflowNodes.values())
+ {
+ sb.append(node.toString(newMargin));
+ }
+
+ namingContexts.toString(leftMargin);
+
+ sb.append(leftMargin + "rootDSEWorkflow:\n");
+ if (rootDSEWorkflowNode == null)
+ {
+ sb.append(newMargin + "null\n");
+ }
+ else
+ {
+ sb.append(rootDSEWorkflowNode.toString(newMargin));
+ }
+
+ return sb;
}
+
/**
- * Registers a workflow with the network group and the workflow may have
- * pre and post workflow element.
+ * Checks whether the base DN of a new workflow to register is present
+ * in a workflow already registered with the network group.
*
- * @param workflow the workflow to register
- * @param preWorkflowElements the tasks to execute before the workflow
- * @param postWorkflowElements the tasks to execute after the workflow
- *
- * @throws DirectoryException If the workflow ID for the provided
- * workflow conflicts with the workflow ID of an existing
- * workflow or if the base DN of the workflow is the same
- * than the base DN of another workflow already registered
+ * @param workflowNode
+ * the workflow to check
+ * @throws DirectoryException
+ * If the base DN of the workflow is already present in the
+ * network group
*/
- private void registerWorkflow(
- WorkflowImpl workflow,
+ private void checkWorkflowBaseDN(WorkflowTopologyNode workflowNode)
+ throws DirectoryException
+ {
+ String workflowID = workflowNode.getWorkflowImpl().getWorkflowId();
+ ensureNotNull(workflowID);
+
+ // If the network group is the "internal" network group then bypass
+ // the check because the internal network group may contain
+ // duplicates of base DNs.
+ if (isInternalNetworkGroup)
+ {
+ return;
+ }
+
+ // If the network group is the "admin" network group then bypass
+ // the check because the internal network group may contain
+ // duplicates of base DNs.
+ if (isAdminNetworkGroup)
+ {
+ return;
+ }
+
+ // The workflow base DN should not be already present in the
+ // network group. Bypass the check for the private workflows...
+ for (WorkflowTopologyNode node : registeredWorkflowNodes.values())
+ {
+ DN nodeBaseDN = node.getBaseDN();
+ if (nodeBaseDN.equals(workflowNode.getBaseDN()))
+ {
+ // The base DN is already registered in the network group,
+ // we must reject the registration request
+ Message message =
+ ERR_REGISTER_WORKFLOW_BASE_DN_ALREADY_EXISTS.get(
+ workflowID, networkGroupID, node.getWorkflowImpl()
+ .getWorkflowId(), workflowNode.getWorkflowImpl()
+ .getBaseDN().toString());
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ message);
+ }
+ }
+ }
+
+
+
+ // Creates and registers the provided network group policy
+ // configuration.
+ private void createNetworkGroupQOSPolicy(
+ QOSPolicyCfg policyConfiguration) throws ConfigException,
+ InitializationException
+ {
+ String className = policyConfiguration.getJavaClass();
+ QOSPolicyCfgDefn d = QOSPolicyCfgDefn.getInstance();
+ ClassPropertyDefinition pd = d.getJavaClassPropertyDefinition();
+
+ // Load the class and cast it to a network group policy.
+ Class<? extends QOSPolicyFactory> theClass;
+ QOSPolicyFactory factory;
+
+ try
+ {
+ theClass = pd.loadClass(className, QOSPolicyFactory.class);
+ factory = theClass.newInstance();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message =
+ ERR_CONFIG_NETWORK_GROUP_POLICY_CANNOT_INITIALIZE.get(String
+ .valueOf(className), String.valueOf(policyConfiguration
+ .dn()), stackTraceToSingleLineString(e));
+ throw new InitializationException(message, e);
+ }
+
+ // Perform the necessary initialization for the network group
+ // policy.
+ QOSPolicy policy;
+
+ try
+ {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ Method method =
+ theClass.getMethod("createQOSPolicy", policyConfiguration
+ .configurationClass());
+
+ policy = (QOSPolicy) method.invoke(factory, policyConfiguration);
+ }
+ catch (Exception e)
+ {
+ if (e instanceof InvocationTargetException)
+ {
+ Throwable t = e.getCause();
+
+ if (t instanceof InitializationException)
+ {
+ throw (InitializationException) t;
+ }
+ else if (t instanceof ConfigException)
+ {
+ throw (ConfigException) t;
+ }
+ }
+
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ Message message =
+ ERR_CONFIG_NETWORK_GROUP_POLICY_CANNOT_INITIALIZE.get(String
+ .valueOf(className), String.valueOf(policyConfiguration
+ .dn()), stackTraceToSingleLineString(e));
+ throw new InitializationException(message, e);
+ }
+
+ // The network group has been successfully initialized - so register
+ // it.
+ QOSPolicy oldPolicy =
+ policies.put(policyConfiguration.dn(), policy);
+
+ if (policy instanceof RequestFilteringPolicy)
+ {
+ requestFilteringPolicy = (RequestFilteringPolicy) policy;
+ }
+ else if (policy instanceof ResourceLimitsPolicy)
+ {
+ resourceLimitsPolicy = (ResourceLimitsPolicy) policy;
+ }
+
+ if (oldPolicy != null)
+ {
+ oldPolicy.finalizeQOSPolicy();
+ }
+ }
+
+
+
+ /**
+ * Deregisters a workflow node with the network group.
+ *
+ * @param workflow
+ * the workflow node to deregister
+ * @return <code>true</code> when the workflow has been successfully
+ * deregistered
+ */
+ private boolean deregisterWorkflow(Workflow workflow)
+ {
+ // true as soon as the workflow has been deregistered
+ boolean deregistered = false;
+
+ // Is it the rootDSE workflow?
+ if (workflow == rootDSEWorkflowNode)
+ {
+ rootDSEWorkflowNode = null;
+ deregistered = true;
+ }
+ else
+ {
+ // Deregister the workflow with the network group.
+ WorkflowTopologyNode workflowNode =
+ (WorkflowTopologyNode) workflow;
+ deregisterWorkflowNode(workflowNode);
+ deregistered = true;
+
+ // The workflow to deregister is not the root DSE workflow.
+ // Remove it from the workflow topology.
+ workflowNode.remove();
+
+ // Rebuild the list of naming context handled by the network group
+ rebuildNamingContextList();
+ }
+
+ return deregistered;
+ }
+
+
+
+ /**
+ * Deregisters the current workflow (this) with the server.
+ *
+ * @param workflowNode
+ * the workflow node to deregister
+ */
+ private void deregisterWorkflowNode(WorkflowTopologyNode workflowNode)
+ {
+ synchronized (registeredWorkflowNodesLock)
+ {
+ TreeMap<String, WorkflowTopologyNode> newWorkflowNodes =
+ new TreeMap<String, WorkflowTopologyNode>(
+ registeredWorkflowNodes);
+ newWorkflowNodes.remove(workflowNode.getWorkflowImpl()
+ .getWorkflowId());
+ registeredWorkflowNodes = newWorkflowNodes;
+ }
+ }
+
+
+
+ /**
+ * Retrieves the list of registered workflows.
+ *
+ * @return a list of workflow ids
+ */
+ private List<String> getRegisteredWorkflows()
+ {
+ List<String> workflowIDs = new ArrayList<String>();
+ synchronized (registeredWorkflowNodesLock)
+ {
+ for (WorkflowTopologyNode node : registeredWorkflowNodes.values())
+ {
+ workflowIDs.add(node.getWorkflowImpl().getWorkflowId());
+ }
+ }
+ return workflowIDs;
+ }
+
+
+
+ /**
+ * We've seen parts of the server hold references to a NetworkGroup
+ * during an in-core server restart. To help detect when this happens,
+ * we null out the member variables, so we will fail fast with an NPE
+ * if an invalidate NetworkGroup is used.
+ */
+ private void invalidate()
+ {
+ namingContexts = null;
+ rootDSEWorkflowNode = null;
+ registeredWorkflowNodes = null;
+ }
+
+
+
+ /**
+ * Checks whether the connection matches the network group criteria.
+ *
+ * @param connection
+ * the client connection
+ * @return a boolean indicating the match
+ */
+ private boolean match(ClientConnection connection)
+ {
+ if (criteria != null)
+ {
+ return criteria.matches(connection);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Checks whether the client connection matches the criteria after
+ * bind.
+ *
+ * @param connection
+ * the ClientConnection
+ * @param bindDN
+ * the DN used to bind
+ * @param authType
+ * the authentication type
+ * @param isSecure
+ * a boolean indicating whether the connection is secure
+ * @return a boolean indicating whether the connection matches the
+ * criteria
+ */
+ private boolean matchAfterBind(ClientConnection connection,
+ DN bindDN, AuthenticationType authType, boolean isSecure)
+ {
+ if (criteria != null)
+ {
+ return criteria.willMatchAfterBind(connection, bindDN, authType,
+ isSecure);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+
+
+ /**
+ * Rebuilds the list of naming contexts handled by the network group.
+ * This operation should be performed whenever a workflow topology has
+ * been updated (workflow registration or de-registration).
+ */
+ private void rebuildNamingContextList()
+ {
+ // reset lists of naming contexts
+ namingContexts.resetLists();
+
+ // a registered workflow with no parent is a naming context
+ for (WorkflowTopologyNode workflowNode : registeredWorkflowNodes
+ .values())
+ {
+ WorkflowTopologyNode parent = workflowNode.getParent();
+ if (parent == null)
+ {
+ namingContexts.addNamingContext(workflowNode);
+ }
+ }
+ }
+
+
+
+ /**
+ * Registers a workflow with the network group and the workflow may
+ * have pre and post workflow element.
+ *
+ * @param workflow
+ * the workflow to register
+ * @param preWorkflowElements
+ * the tasks to execute before the workflow
+ * @param postWorkflowElements
+ * the tasks to execute after the workflow
+ * @throws DirectoryException
+ * If the workflow ID for the provided workflow conflicts
+ * with the workflow ID of an existing workflow or if the
+ * base DN of the workflow is the same than the base DN of
+ * another workflow already registered
+ */
+ private void registerWorkflow(WorkflowImpl workflow,
WorkflowElement<?>[] preWorkflowElements,
- WorkflowElement<?>[] postWorkflowElements
- ) throws DirectoryException
+ WorkflowElement<?>[] postWorkflowElements)
+ throws DirectoryException
{
// Is it the rootDSE workflow?
DN baseDN = workflow.getBaseDN();
if (baseDN.isNullDN())
{
- // NOTE - The rootDSE workflow is stored with the registeredWorkflows.
+ // NOTE - The rootDSE workflow is stored with the
+ // registeredWorkflows.
rootDSEWorkflowNode =
- new RootDseWorkflowTopology(workflow, namingContexts);
+ new RootDseWorkflowTopology(workflow, namingContexts);
}
else
{
- // This workflow is not the rootDSE workflow. Try to insert it in the
- // workflow topology.
- WorkflowTopologyNode workflowNode = new WorkflowTopologyNode(
- workflow, preWorkflowElements, postWorkflowElements);
+ // This workflow is not the rootDSE workflow. Try to insert it in
+ // the workflow topology.
+ WorkflowTopologyNode workflowNode =
+ new WorkflowTopologyNode(workflow, preWorkflowElements,
+ postWorkflowElements);
- // Register the workflow node with the network group. If the workflow
- // ID is already existing then an exception is raised.
+ // Register the workflow node with the network group. If the
+ // workflow ID is already existing then an exception is raised.
registerWorkflowNode(workflowNode);
// Now add the workflow in the workflow topology...
- for (WorkflowTopologyNode curNode: registeredWorkflowNodes.values())
+ for (WorkflowTopologyNode curNode : registeredWorkflowNodes
+ .values())
{
// Try to insert the new workflow under an existing workflow...
if (curNode.insertSubordinate(workflowNode))
@@ -350,10 +1923,9 @@
// Now that the workflow node has been registered with the network
// group, update the reference counter of the workflow, unless
- // the network group is either default, or administration, or internal
- // network group.
- if (!isAdminNetworkGroup
- && !isInternalNetworkGroup
+ // the network group is either default, or administration, or
+ // internal network group.
+ if (!isAdminNetworkGroup && !isInternalNetworkGroup
&& !isDefaultNetworkGroup)
{
workflow.incrementReferenceCounter();
@@ -362,196 +1934,19 @@
}
- /**
- * Deregisters a workflow with the network group. The workflow to
- * deregister is identified by its baseDN.
- *
- * @param baseDN the baseDN of the workflow to deregister, may be null
- *
- * @return the deregistered workflow
- */
- public Workflow deregisterWorkflow(
- DN baseDN
- )
- {
- Workflow workflow = null;
-
- if (baseDN == null)
- {
- return workflow;
- }
-
- if (baseDN.isNullDN())
- {
- // deregister the rootDSE
- deregisterWorkflow(rootDSEWorkflowNode);
- workflow = rootDSEWorkflowNode.getWorkflowImpl();
- }
- else
- {
- // deregister a workflow node
- synchronized (registeredWorkflowNodesLock)
- {
- for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
- {
- DN curDN = node.getBaseDN();
- if (curDN.equals(baseDN))
- {
- // Call deregisterWorkflow() instead of deregisterWorkflowNode()
- // because we want the naming context list to be updated as well.
- deregisterWorkflow(node);
- workflow = node.getWorkflowImpl();
-
- // Only one workflow can match the baseDN, so we can break
- // the loop here.
- break;
- }
- }
- }
- }
-
- // Now that the workflow node has been deregistered with the network
- // group, update the reference counter of the workflow.
- if ((workflow != null)
- && !isAdminNetworkGroup
- && !isInternalNetworkGroup
- && !isDefaultNetworkGroup)
- {
- WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
- workflowImpl.decrementReferenceCounter();
- }
-
- return workflow;
- }
-
-
- /**
- * Deregisters a workflow with the network group. The workflow to
- * deregister is identified by its workflow ID.
- *
- * @param workflowID the workflow identifier of the workflow to deregister
- * @return the deregistered workflow
- */
- public Workflow deregisterWorkflow(
- String workflowID
- )
- {
- Workflow workflow = null;
-
- String rootDSEWorkflowID = null;
- if (rootDSEWorkflowNode != null)
- {
- rootDSEWorkflowID = rootDSEWorkflowNode.getWorkflowImpl().getWorkflowId();
- }
-
- if (workflowID.equalsIgnoreCase(rootDSEWorkflowID))
- {
- // deregister the rootDSE
- deregisterWorkflow(rootDSEWorkflowNode);
- workflow = rootDSEWorkflowNode.getWorkflowImpl();
- }
- else
- {
- // deregister a workflow node
- synchronized (registeredWorkflowNodesLock)
- {
- for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
- {
- String curID = node.getWorkflowImpl().getWorkflowId();
- if (curID.equals(workflowID))
- {
- // Call deregisterWorkflow() instead of deregisterWorkflowNode()
- // because we want the naming context list to be updated as well.
- deregisterWorkflow(node);
- workflow = node.getWorkflowImpl();
-
- // Only one workflow can match the baseDN, so we can break
- // the loop here.
- break;
- }
- }
- }
- }
-
- // Now that the workflow node has been deregistered with the network
- // group, update the reference counter of the workflow.
- if ((workflow != null)
- && !isAdminNetworkGroup
- && !isInternalNetworkGroup
- && !isDefaultNetworkGroup)
- {
- WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
- workflowImpl.decrementReferenceCounter();
- }
-
- return workflow;
- }
-
-
- /**
- * Deregisters a workflow node with the network group.
- *
- * @param workflow the workflow node to deregister
- * @return <code>true</code> when the workflow has been successfully
- * deregistered
- */
- private boolean deregisterWorkflow(Workflow workflow)
- {
- // true as soon as the workflow has been deregistered
- boolean deregistered = false;
-
- // Is it the rootDSE workflow?
- if (workflow == rootDSEWorkflowNode)
- {
- rootDSEWorkflowNode = null;
- deregistered = true;
- }
- else
- {
- // Deregister the workflow with the network group.
- WorkflowTopologyNode workflowNode = (WorkflowTopologyNode) workflow;
- deregisterWorkflowNode(workflowNode);
- deregistered = true;
-
- // The workflow to deregister is not the root DSE workflow.
- // Remove it from the workflow topology.
- workflowNode.remove();
-
- // Rebuild the list of naming context handled by the network group
- rebuildNamingContextList();
- }
-
- return deregistered;
- }
-
-
- /**
- * Retrieves the list of registered workflows.
- * @return a list of workflow ids
- */
- public List<String> getRegisteredWorkflows() {
- List<String> workflowIDs = new ArrayList<String>();
- synchronized (registeredWorkflowNodesLock) {
- for (WorkflowTopologyNode node : registeredWorkflowNodes.values()) {
- workflowIDs.add(node.getWorkflowImpl().getWorkflowId());
- }
- }
- return workflowIDs;
- }
-
/**
* Registers a workflow node with the network group.
*
- * @param workflowNode the workflow node to register
- *
- * @throws DirectoryException If the workflow node ID for the provided
- * workflow node conflicts with the workflow
- * node ID of an existing workflow node.
+ * @param workflowNode
+ * the workflow node to register
+ * @throws DirectoryException
+ * If the workflow node ID for the provided workflow node
+ * conflicts with the workflow node ID of an existing
+ * workflow node.
*/
- private void registerWorkflowNode(
- WorkflowTopologyNode workflowNode
- ) throws DirectoryException
+ private void registerWorkflowNode(WorkflowTopologyNode workflowNode)
+ throws DirectoryException
{
String workflowID = workflowNode.getWorkflowImpl().getWorkflowId();
ensureNotNull(workflowID);
@@ -561,10 +1956,11 @@
// The workflow must not be already registered
if (registeredWorkflowNodes.containsKey(workflowID))
{
- Message message = ERR_REGISTER_WORKFLOW_NODE_ALREADY_EXISTS.get(
- workflowID, networkGroupID);
- throw new DirectoryException(
- ResultCode.UNWILLING_TO_PERFORM, message);
+ Message message =
+ ERR_REGISTER_WORKFLOW_NODE_ALREADY_EXISTS.get(workflowID,
+ networkGroupID);
+ throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
+ message);
}
// The workflow base DN should not be already present in the
@@ -573,685 +1969,26 @@
// All is fine, let's register the workflow
TreeMap<String, WorkflowTopologyNode> newRegisteredWorkflowNodes =
- new TreeMap<String, WorkflowTopologyNode>(registeredWorkflowNodes);
+ new TreeMap<String, WorkflowTopologyNode>(
+ registeredWorkflowNodes);
newRegisteredWorkflowNodes.put(workflowID, workflowNode);
registeredWorkflowNodes = newRegisteredWorkflowNodes;
}
}
- /**
- * Checks whether the base DN of a new workflow to register is
- * present in a workflow already registered with the network group.
- *
- * @param workflowNode the workflow to check
- *
- * @throws DirectoryException If the base DN of the workflow is already
- * present in the network group
- */
- private void checkWorkflowBaseDN(
- WorkflowTopologyNode workflowNode
- ) throws DirectoryException
- {
- String workflowID = workflowNode.getWorkflowImpl().getWorkflowId();
- ensureNotNull(workflowID);
-
- // If the network group is the "internal" network group then bypass
- // the check because the internal network group may contain duplicates
- // of base DNs.
- if (isInternalNetworkGroup)
- {
- return;
- }
-
- // If the network group is the "admin" network group then bypass
- // the check because the internal network group may contain duplicates
- // of base DNs.
- if (isAdminNetworkGroup)
- {
- return;
- }
-
- // The workflow base DN should not be already present in the
- // network group. Bypass the check for the private workflows...
- for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
- {
- DN nodeBaseDN = node.getBaseDN();
- if (nodeBaseDN.equals(workflowNode.getBaseDN()))
- {
- // The base DN is already registered in the network group,
- // we must reject the registration request
- Message message = ERR_REGISTER_WORKFLOW_BASE_DN_ALREADY_EXISTS.get(
- workflowID,
- networkGroupID,
- node.getWorkflowImpl().getWorkflowId(),
- workflowNode.getWorkflowImpl().getBaseDN().toString());
- throw new DirectoryException(
- ResultCode.UNWILLING_TO_PERFORM, message);
- }
- }
- }
-
-
- /**
- * Deregisters the current workflow (this) with the server.
- *
- * @param workflowNode the workflow node to deregister
- */
- private void deregisterWorkflowNode(
- WorkflowTopologyNode workflowNode
- )
- {
- synchronized (registeredWorkflowNodesLock)
- {
- TreeMap<String, WorkflowTopologyNode> newWorkflowNodes =
- new TreeMap<String, WorkflowTopologyNode>(registeredWorkflowNodes);
- newWorkflowNodes.remove(workflowNode.getWorkflowImpl().getWorkflowId());
- registeredWorkflowNodes = newWorkflowNodes;
- }
- }
-
-
- /**
- * Adds a connection to the group.
- *
- * @param connection the ClientConnection
- */
- public void addConnection(ClientConnection connection) {
- if (resourceLimits != null) {
- resourceLimits.addConnection(connection);
- }
- }
-
- /**
- * Removes a connection from the group.
- *
- * @param connection the ClientConnection
- */
- public void removeConnection(ClientConnection connection) {
- if (resourceLimits != null) {
- resourceLimits.removeConnection(connection);
- }
- }
-
- /**
- *
- * Sets the network group priority.
- *
- * @param prio the network group priority
- */
- public void setNetworkGroupPriority(int prio) {
- // Check whether the priority has changed
- if (priority != prio) {
- synchronized (registeredNetworkGroupsLock)
- {
- priority = prio;
-
- // Nothing to do if the network group is not registered
- if (registeredNetworkGroups.containsKey(networkGroupID)) {
- // If the network group was already registered, remove it from the
- // ordered list
- orderedNetworkGroups.remove(this);
-
- // Then insert it at the right position in the ordered list
- int index = 0;
- for (NetworkGroup ng : registeredNetworkGroups.values()) {
- if (ng.equals(this)) {
- continue;
- }
- if (this.priority > ng.priority) {
- index++;
- }
- }
- orderedNetworkGroups.add(index, this);
- }
- }
- }
- }
-
- /**
- *
- * Sets the network group criteria.
- *
- * @param ngCriteria the criteria
- */
- public void setCriteria(NetworkGroupCriteria ngCriteria) {
- criteria = ngCriteria;
- }
-
- /**
- * Sets the Resource Limits.
- *
- * @param limits the new resource limits
- */
- public void setResourceLimits(ResourceLimits limits) {
- resourceLimits = limits;
- }
-
-
- /**
- * Sets the Request Filtering Policy.
- *
- * @param policy the new request filtering policy
- */
- public void setRequestFilteringPolicy(RequestFilteringPolicy policy) {
- requestFilteringPolicy = policy;
- }
-
- /**
- * Sets the affinity policy. The client connection affinity is the ability
- * for the server to bypass a route algorithm like "load balancing" so
- * that a request is always sent to the same data source regardless the
- * route algorithm.
- *
- * @param affinityPolicy
- * The client connection affinity policy of the network group.
- */
- public void setAffinityPolicy(
- ClientConnectionAffinityPolicy affinityPolicy)
- {
- this.affinityPolicy = affinityPolicy;
- }
-
- /**
- * Sets the affinity timeout value. The client connection affinity, when
- * set, remains active until the time out expires. When the time out
- * value is set to 0 then an active affinity never expires.
- *
- * @param timeout
- * The affinity timeout value (0 means never expire).
- */
- public void setAffinityTimeout(long timeout)
- {
- this.affinityTimeout = timeout;
- }
-
- /**
- * Gets the highest priority matching network group.
- *
- * @param connection the client connection
- * @return matching network group
- */
- public static NetworkGroup findMatchingNetworkGroup(
- ClientConnection connection) {
- for (NetworkGroup ng : getOrderedNetworkGroups()) {
- if (ng.match(connection)) {
- return ng;
- }
- }
- return defaultNetworkGroup;
- }
-
- /**
- * Gets the highest priority matching network group for a BIND op.
- *
- * @param connection the client connection
- * @param dn the operation bindDN
- * @param authType the operation authentication type
- * @param isSecure a boolean indicating whether the operation is secured
- * @return matching network group
- */
- public static NetworkGroup findBindMatchingNetworkGroup(
- ClientConnection connection, DN dn, AuthenticationType authType,
- boolean isSecure) {
- for (NetworkGroup ng:getOrderedNetworkGroups()) {
- if (ng.matchAfterBind(connection, dn, authType, isSecure)) {
- return ng;
- }
- }
- return defaultNetworkGroup;
- }
-
- /**
- * Checks whether the connection matches the network group criteria.
- *
- * @param connection the client connection
- * @return a boolean indicating the match
- */
- private boolean match(ClientConnection connection) {
- if (criteria != null) {
- return (criteria.match(connection));
- }
- return (true);
- }
-
- /**
- * Checks whether the client connection matches the criteria after bind.
- *
- * @param connection the ClientConnection
- * @param bindDN the DN used to bind
- * @param authType the authentication type
- * @param isSecure a boolean indicating whether the connection is secure
- * @return a boolean indicating whether the connection matches the criteria
- */
- private boolean matchAfterBind(ClientConnection connection, DN bindDN,
- AuthenticationType authType, boolean isSecure) {
- if (criteria != null) {
- return (criteria.matchAfterBind(connection, bindDN, authType, isSecure));
- }
- return (true);
- }
-
-
- /**
- * Checks the resource limits.
- *
- * @param connection the client connection
- * @param operation the ongoing operation
- * @param fullCheck a boolean indicating the level of checking: full/partial
- * @param messages the messages indicating the cause of the failure.
- * @return a boolean indicating whether resource limits are exceeded
- */
- public boolean checkResourceLimits(
- ClientConnection connection,
- PreParseOperation operation,
- boolean fullCheck,
- List<Message> messages)
- {
- if (resourceLimits != null) {
- return (resourceLimits.checkLimits(connection, operation,
- fullCheck, messages));
- }
- return (true);
- }
-
- /**
- * Gets the search size limit, i.e. the maximum number of entries returned
- * by a search.
- * @return the maximum number of entries returned by a search
- */
- public int getSearchSizeLimit() {
- if (resourceLimits != null) {
- return resourceLimits.getSizeLimit();
- }
- return -1;
- }
-
- /**
- * Gets the search duration limit, i.e. the maximum duration of a search
- * operation.
- * @return the maximum duration in ms of a search operation
- */
- public int getSearchDurationLimit() {
- if (resourceLimits != null) {
- return resourceLimits.getTimeLimit();
- }
- return -1;
- }
-
- /**
- * Gets the minimum string length of a substring filter in a search
- * operation.
- * @return the minimum substring length
- */
- public int getMinSubstring() {
- if (resourceLimits != null) {
- return resourceLimits.getMinSubstring();
- }
- return 0;
- }
-
- /**
- * Gets the referral policy. The referral policy defines the behavior
- * when a referral or a search continuation reference is received.
- * The referral can either be discarded (ie an error is returned to the
- * client), forwarded (ie the result is passed as-is to the client) or
- * followed (ie the server contacts the server targeted by the referral to
- * pursue the request).
- * @return the referral policy for this network group
- */
- public ReferralPolicy getReferralPolicy() {
- if (resourceLimits != null) {
- return resourceLimits.getReferralPolicy();
- }
- return ReferralPolicy.FORWARD;
- }
-
- /**
- * Gets the referral bind policy. The referral bind policy defines
- * the bind credentials used when the server tries to follow a referral. It
- * can either bind to the referred server anonymously, or using the same
- * credentials as in the original request.
- * @return the referral binf policy
- */
- public ReferralBindPolicy getReferralBindPolicy() {
- if (resourceLimits != null) {
- return resourceLimits.getReferralBindPolicy();
- }
- return ReferralBindPolicy.ANONYMOUS;
- }
-
- /**
- * Gets the referral hop limit. When configured to follow referrals,
- * the request to the referred server can also contain a referral. The hop
- * limit is the maximum number of subsequent operations.
- * @return the referral hop limit
- */
- public int getReferralHopLimit() {
- if (resourceLimits != null) {
- return resourceLimits.getReferralHopLimit();
- }
- return 0;
- }
-
- /**
- * Gets the affinity policy. The client connection affinity is the ability
- * for the server to bypass a route algorithm like "load balancing" so
- * that a request is always sent to the same data source regardless the
- * route algorithm.
- *
- * @return the client connection affinity policy of the network group
- */
- public ClientConnectionAffinityPolicy getAffinityPolicy()
- {
- return this.affinityPolicy;
- }
-
- /**
- * Gets the affinity timeout value. The client connection affinity, when
- * set, is active for a period of time. Once that period of time has
- * expired, the client connection affinity is reset. A value of 0 means
- * "no limit" - when an affinity is set it remains active for ever.
- *
- * @return the affinity timeout value (0 means no limit).
- */
- public long getAffinityTimeout()
- {
- return this.affinityTimeout;
- }
-
- /**
- * Checks the request filtering policy.
- * @param operation the operation to be checked
- * @param messages the error messages
- * @return boolean indicating whether the operation conforms to the
- * network group request filtering policy
- */
- public boolean checkRequestFilteringPolicy(
- PreParseOperation operation,
- List<Message> messages) {
- if (requestFilteringPolicy != null) {
- return requestFilteringPolicy.checkPolicy(operation, messages);
- }
- return true;
- }
-
-
- /**
- * Gets the highest workflow in the topology that can handle the baseDN.
- *
- * @param baseDN the base DN of the request
- * @return the highest workflow in the topology that can handle the base DN,
- * <code>null</code> if none was found
- */
- public Workflow getWorkflowCandidate(
- DN baseDN
- )
- {
- // the top workflow to return
- Workflow workflowCandidate = null;
-
- // get the list of workflow candidates
- if (baseDN.isNullDN())
- {
- // The rootDSE workflow is the candidate.
- workflowCandidate = rootDSEWorkflowNode;
- }
- else
- {
- // Search the highest workflow in the topology that can handle
- // the baseDN.
- for (WorkflowTopologyNode curWorkflow: namingContexts.getNamingContexts())
- {
- workflowCandidate = curWorkflow.getWorkflowCandidate (baseDN);
- if (workflowCandidate != null)
- {
- break;
- }
- }
- }
-
- return workflowCandidate;
- }
-
-
- /**
- * Returns the default network group. The default network group is always
- * defined and has no criterion, no policy and provide full access to
- * all the registered workflows.
- *
- * @return the default network group
- */
- public static NetworkGroup getDefaultNetworkGroup()
- {
- return defaultNetworkGroup;
- }
-
-
- /**
- * Returns the admin network group.
- * @return the admin network group
- */
- public static NetworkGroup getAdminNetworkGroup()
- {
- return adminNetworkGroup;
- }
-
-
- /**
- * Returns the internal network group.
- * @return the internal network group
- */
- public static NetworkGroup getInternalNetworkGroup()
- {
- return internalNetworkGroup;
- }
-
-
- /**
- * Rebuilds the list of naming contexts handled by the network group.
- * This operation should be performed whenever a workflow topology
- * has been updated (workflow registration or de-registration).
- */
- private void rebuildNamingContextList()
- {
- // reset lists of naming contexts
- namingContexts.resetLists();
-
- // a registered workflow with no parent is a naming context
- for (WorkflowTopologyNode workflowNode: registeredWorkflowNodes.values())
- {
- WorkflowTopologyNode parent = workflowNode.getParent();
- if (parent == null)
- {
- namingContexts.addNamingContext (workflowNode);
- }
- }
- }
-
-
- /**
- * Returns the list of naming contexts handled by the network group.
- *
- * @return the list of naming contexts
- */
- public NetworkGroupNamingContexts getNamingContexts()
- {
- return namingContexts;
- }
-
-
- /**
- * Dumps info from the current network group for debug purpose.
- *
- * @param leftMargin white spaces used to indent traces
- * @return a string buffer that contains trace information
- */
- public StringBuilder toString(String leftMargin)
- {
- StringBuilder sb = new StringBuilder();
- String newMargin = leftMargin + " ";
-
- sb.append (leftMargin + "Networkgroup (" + networkGroupID+ "\n");
- sb.append (leftMargin + "List of registered workflows:\n");
- for (WorkflowTopologyNode node: registeredWorkflowNodes.values())
- {
- sb.append (node.toString (newMargin));
- }
-
- namingContexts.toString (leftMargin);
-
- sb.append (leftMargin + "rootDSEWorkflow:\n");
- if (rootDSEWorkflowNode == null)
- {
- sb.append (newMargin + "null\n");
- }
- else
- {
- sb.append (rootDSEWorkflowNode.toString (newMargin));
- }
-
- return sb;
- }
-
-
- /**
- * Deregisters all network groups that have been registered. This should be
- * called when the server is shutting down.
- */
- public static void deregisterAllOnShutdown()
- {
- synchronized (registeredNetworkGroupsLock)
- {
- // Invalidate all NetworkGroups so they cannot accidentally be used
- // after a restart.
- Collection<NetworkGroup> networkGroups = registeredNetworkGroups.values();
- for (NetworkGroup networkGroup: networkGroups)
- {
- networkGroup.invalidate();
- }
- defaultNetworkGroup.invalidate();
- adminNetworkGroup.invalidate();
- internalNetworkGroup.invalidate();
-
- registeredNetworkGroups = new TreeMap<String,NetworkGroup>();
- orderedNetworkGroups = new ArrayList<NetworkGroup>();
- defaultNetworkGroup = new NetworkGroup ("default");
- adminNetworkGroup = new NetworkGroup ("admin");
- internalNetworkGroup = new NetworkGroup("internal");
- }
- }
-
- /**
- * We've seen parts of the server hold references to a NetworkGroup
- * during an in-core server restart. To help detect when this happens,
- * we null out the member variables, so we will fail fast with an NPE if an
- * invalidate NetworkGroup is used.
- */
- private void invalidate()
- {
- namingContexts = null;
- networkGroupID = null;
- rootDSEWorkflowNode = null;
- registeredWorkflowNodes = null;
- }
-
-
- /**
- * Provides the list of network group registered with the server.
- *
- * @return the list of registered network groups
- */
- public static Collection<NetworkGroup> getRegisteredNetworkGroups()
- {
- return registeredNetworkGroups.values();
- }
-
-
- /**
- * Provides the ordered list of registered Network groups.
- *
- * @return the ordered list of registered network groups
- */
- private static List<NetworkGroup> getOrderedNetworkGroups()
- {
- return orderedNetworkGroups;
- }
-
-
- /**
- * Returns a specific NetworkGroup.
- *
- * @param networkGroupId the identifier of the requested network group
- * @return the requested NetworkGroup
- */
- public static NetworkGroup getNetworkGroup(String networkGroupId)
- {
- return registeredNetworkGroups.get(networkGroupId);
- }
-
-
- /**
- * Resets the configuration of all the registered network groups.
- */
- public static void resetConfig()
- {
- // Reset the default network group
- defaultNetworkGroup.reset();
- adminNetworkGroup.reset();
- internalNetworkGroup.reset();
-
- // Reset all the registered network group
- synchronized (registeredNetworkGroupsLock)
- {
- registeredNetworkGroups = new TreeMap<String, NetworkGroup>();
- orderedNetworkGroups = new ArrayList<NetworkGroup>();
- }
- }
-
/**
* Resets the configuration of the current network group.
*/
- public void reset()
+ private void reset()
{
synchronized (registeredWorkflowNodesLock)
{
- registeredWorkflowNodes = new TreeMap<String, WorkflowTopologyNode>();
+ registeredWorkflowNodes =
+ new TreeMap<String, WorkflowTopologyNode>();
rootDSEWorkflowNode = null;
namingContexts = new NetworkGroupNamingContexts();
}
}
-
- /**
- * Retrieves the statistics associated to the request filtering policy.
- *
- * @return the statistics associated to the request filtering policy
- */
- public RequestFilteringPolicyStat getRequestFilteringPolicyStat() {
- if (requestFilteringPolicy != null) {
- return requestFilteringPolicy.getStat();
- }
- return null;
- }
-
- /**
- * Retrieves the statistics associated to the resource limits.
- *
- * @return the statistics associated to the resource limits
- */
- public ResourceLimitsStat getResourceLimitStat() {
- if (resourceLimits != null) {
- return resourceLimits.getStat();
- }
- return null;
- }
-
- /**
- * Updates the operations statistics.
- * @param message The LDAP message being processed
- */
- public void updateMessageRead(LDAPMessage message) {
- stats.updateMessageRead(message);
- }
}
--
Gitblit v1.10.0