DataLayer.java revision e6c3a72a023407f5d1fface64356e1cc81f1af31
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: DataLayer.java,v 1.19 2009/11/20 23:52:52 ww203982 Exp $
*
* Portions Copyrighted 2011-2016 ForgeRock AS.
*/
/**
* DataLayer (A PACKAGE SCOPE CLASS) to access LDAP or other database
*
* TODO: 1. Needs to subclass and isolate the current implementation of
* DataLayer as DSLayer for ldap specific operations 2. Improvements needed for
* _ldapPool: destroy(), initial bind user, tunning for MIN and MAX initial
* settings etc 3. May choose to extend implementation of _ldapPool from
* LDAPConnectionPool so that there is load balance between connections. Also
* _ldapPool may be implemented with a HashTable of (host,port) for mulitple
* pools of connections for mulitple (host,port) to DS servers instead of single
* host and port.
*
* @supported.api
*/
/**
* Static section to retrieve the debug object.
*/
private static DataLayerConfigListener configListener;
/**
* Default minimal connections if none is defined in configuration
*/
/**
* Default maximum connections if none is defined in configuration
*/
static final int MAX_CONN = 20;
/**
* Default maximum backlog queue size
*/
static final int MAX_BACKLOG = 100;
static final String LDAP_RELEASECONNBEFORESEARCH =
"releaseconnectionbeforesearchcompletes";
private static int replicaRetryNum = 1;
private static long replicaRetryInterval = 1000;
private static final String LDAP_CONNECTION_NUM_RETRIES =
"com.iplanet.am.ldap.connection.num.retries";
private static final String LDAP_CONNECTION_RETRY_INTERVAL =
"com.iplanet.am.ldap.connection.delay.between.retries";
private static final String LDAP_CONNECTION_ERROR_CODES =
"com.iplanet.am.ldap.connection.ldap.error.codes.retries";
private static int connNumRetry = 3;
private static int connRetryInterval = 1000;
static {
}
public static void initConnectionParams() {
if (numRetryStr != null) {
try {
} catch (NumberFormatException e) {
if (debug.warningEnabled()) {
}
}
}
if (retryIntervalStr != null) {
try {
} catch (NumberFormatException e) {
if (debug.warningEnabled()) {
}
}
}
while (stz.hasMoreTokens()) {
}
}
if (debug.messageEnabled()) {
}
}
/**
* DataLayer constructor
*/
private DataLayer() {
}
/**
* Constructor given the extra parameter of guid and pwd identifying an
* authenticated principal
*
* @param host
* LDAP host
* @param port
* LDAP port
* @param pwd
* Password for the user
*/
throws UMSException {
m_proxyUser = id;
configListener = new DataLayerConfigListener();
initLdapPool();
}
/**
* Create the singleton DataLayer object if it doesn't exist already.
*
* @supported.api
*/
throws UMSException {
// Make sure only one instance of this class is created.
if (m_instance == null) {
int port = 389;
}
// Start the EventService thread if it has not already started.
}
return m_instance;
}
/**
* Create the singleton DataLayer object if it doesn't exist already.
* Assumes the server instance for "LDAPUser.Type.AUTH_PROXY".
*
* @supported.api
*/
// Make sure only one instance of this class is created.
if (m_instance == null) {
try {
} catch (LDAPServiceException ex) {
+ ex.getMessage());
}
}
return m_instance;
}
/**
* Get connection from pool. Reauthenticate if necessary
*
* @return connection that is available to use.
*
* @supported.api
*/
return null;
if (debug.messageEnabled()) {
}
// proxy as given principal
if (debug.messageEnabled()) {
}
return conn;
}
/**
* Returns String values of the attribute.
*
* @param principal Authentication Principal.
* @param guid distinguished name.
* @param attrName attribute name.
*
* @supported.api
*/
SearchRequest request = LDAPRequests.newSearchRequest(id, SearchScope.BASE_OBJECT, "(objectclass=*)");
try {
}
}
} catch (Exception e) {
if (debug.warningEnabled()) {
"Exception in DataLayer.getAttributeString for DN: "
+ id, e);
}
return null;
}
}
/**
* Returns <code>Attr</code> from the given attribute name.
*
* @param principal Authentication Principal.
* @param guid Distinguished name.
* @param attrName Attribute name.
*
* @supported.api
*/
try {
SearchRequest request = LDAPRequests.newSearchRequest(id, SearchScope.BASE_OBJECT, "(objectclass=*)",
attrName);
return null;
} else {
}
}
} catch (Exception e) {
if (debug.warningEnabled()) {
+ id, e);
}
return null;
}
}
/**
* Returns attributes for the given attribute names.
*
* @param principal Authentication Principal.
* @param guid Distinguished name.
* @param attrNames Attribute names.
* @return collection of Attr.
*
* @supported.api
*/
public Collection<Attr> getAttributes(Principal principal, Guid guid, Collection<String> attrNames) {
SearchRequest request = LDAPRequests.newSearchRequest(id, SearchScope.BASE_OBJECT, "(objectclass=*)",
try {
return Collections.emptySet();
}
}
}
}
return attributes;
} catch(Exception e) {
return null;
}
}
/**
* Adds entry to the server.
*
* @param principal Authenticated Principal.
* @param guid Distinguished name.
* @exception AccessRightsException if insufficient access>
* @exception EntryAlreadyExistsException if the entry already exists.
* @exception UMSException if fail to add entry.
*
* @supported.api
*/
public void addEntry(
) throws UMSException {
try {
}
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
return;
} catch (LdapException e) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LdapException e) {
if (debug.warningEnabled()) {
e);
}
} else {
}
}
}
/**
* Delete entry from the server
*
* @param guid
* globally unique identifier for the entry
* @exception AccessRightsException
* insufficient access
* @exception EntryNotFoundException
* if the entry is not found
* @exception UMSException
* Fail to delete the entry
*
* @supported.api
*/
throws UMSException {
throw new IllegalArgumentException(msg);
}
try {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
return;
} catch (LdapException e) {
|| retry == connNumRetry) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LdapException e) {
} else {
}
}
}
/**
* Read an ldap entry
*
* @param guid
* globally unique identifier for the entry
* @return an attribute set representing the entry in ldap, all non
* operational attributes are read
* @exception EntryNotFoundException
* if the entry is not found
* @exception UMSException
* Fail to read the entry
*
* @supported.api
*/
throws UMSException {
}
/**
* Reads an ldap entry.
*
* @param principal Authentication Principal.
* @param guid Globally unique identifier for the entry.
* @param attrNames Attributes to read.
* @return an attribute set representing the entry in LDAP.
* @exception EntryNotFoundException if the entry is not found.
* @exception UMSException if fail to read the entry.
*
* @supported.api
*/
) throws UMSException {
SearchRequest request = LDAPRequests.newSearchRequest(id, SearchScope.BASE_OBJECT, "(objectclass=*)",
if (entryReader == null) {
throw new AccessRightsException(id);
}
if (reader.isReference()) {
//TODO AME-7017
}
}
}
}
} catch (IOException e) {
}
}
throws UMSException {
try {
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
return;
} catch (LdapException e) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LdapException e) {
if (debug.warningEnabled()) {
}
throw new EntryNotFoundException(id, e);
throw new AccessRightsException(id, e);
} else {
throw new UMSException(id, e);
}
}
}
/**
* Modifies an ldap entry.
*
* @param principal Authentication Principal.
* @param guid globally unique identifier for the entry.
* @param modifications Set of modifications for the entry.
* @exception AccessRightsException if insufficient access
* @exception EntryNotFoundException if the entry is not found.
* @exception UMSException if failure
*
* @supported.api
*/
throws UMSException {
try {
}
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
return;
} catch (LdapException e) {
|| retry == connNumRetry) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LdapException e) {
if (debug.warningEnabled()) {
}
throw new EntryNotFoundException(id, e);
throw new AccessRightsException(id, e);
} else {
throw new UMSException(id, e);
}
}
}
/**
* Changes user password.
*
* @param guid globally unique identifier for the entry.
* @param attrName password attribute name
* @param oldPassword old password
* @param newPassword new password
* @exception AccessRightsException if insufficient access
* @exception EntryNotFoundException if the entry is not found.
* @exception UMSException if failure
*
* @supported.api
*/
throws UMSException {
try {
// All connections will use authentication
} catch (LdapException ldex) {
if (debug.warningEnabled()) {
}
} else {
}
}
} catch (LDAPServiceException ex) {
}
}
/**
* Adds value for an attribute and saves the change in the database.
*
* @param principal Authenticated Principal.
* @param guid ID of the entry to which to add the attribute value.
* @param name name of the attribute to which value is being added.
* @param value Value to be added to the attribute.
* @throws UMSException if there is any error while adding the value.
*
* @supported.api
*/
public void addAttributeValue(Principal principal, Guid guid, String name, String value) throws UMSException {
// Delegate to the other modify() method.
}
/**
* Removes value for an attribute and saves the change in the database.
*
* @param principal Authenticated Principal.
* @param guid the id of the entry from which to remove the attribute value.
* @param name Name of the attribute from which value is being removed
* @param value Value to be removed from the attribute.
* @throws UMSException if there is any error while removing the value.
*
* @supported.api
*/
public void removeAttributeValue(Principal principal, Guid guid, String name, String value) throws UMSException {
// Delegate to the other modify() method.
}
private void modifyAttributeValue(ModificationType modType, Principal principal, Guid guid, String name,
// Delegate to the other modify() method.
}
if (searchControl != null) {
}
} else {
}
}
}
return ctrls;
}
return null;
}
/**
* Performs synchronous search based on specified ldap filter. This is low
* level API which assumes caller knows how to construct a data store filer.
*
* @param principal Authenticated Principal.
* @param guid Unique identifier for the entry.
* @param scope Scope can be either <code>SCOPE_ONE</code>,
* <code>SCOPE_SUB</code> or <code>SCOPE_BASE</code>.
* @param searchFilter Search filter for this search.
* @param attrNames Attribute name for retrieving.
* @param attrOnly if true, returns the names but not the values of the
* attributes found.
* @param searchControl Search Control.
* @exception UMSException if failure.
* @exception InvalidSearchFilterException if failure
*
* @supported.api
*/
public SearchResults search(
int scope,
boolean attrOnly,
) throws UMSException {
// always add "objectclass" to attributes to get, to find the right java
// class
} else {
}
// if searchFilter is null, search for everything under the base
if (searchFilter == null) {
searchFilter = "(objectclass=*)";
}
try {
// call readLDAPEntry() only in replica case, save one LDAP search
// assume replica case when replicaRetryNum is not 0
if (replicaRetryNum != 0) {
}
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
/*
* The array {"*"} is used, because LDAPv3 defines
* "*" as a special string indicating all
* attributes. This gets all the attributes.
*/
}
break;
}
}
// TODO: need review and see if conn is recorded properly for
// subsequent use
//
if ((searchControl != null)
}
if (searchControl != null
}
}
return result;
} catch (LdapException e) {
if (debug.warningEnabled()) {
}
throw new InvalidSearchFilterException(searchFilter, e);
} else {
throw new UMSException(msg, e);
}
}
}
/**
* Perform synchronous search based on specified ldap filter. This is low
* level API which assumes caller knows how to construct a data store filer.
*
* @param principal Authenticated Principal.
* @param guid Unique identifier for the entry
* @param scope Scope can be either <code>SCOPE_ONE</code>,
* <code>SCOPE_SUB</code>, <code>SCOBE_BASE</code>
* @param searchFilter Search filter for this search.
* @param searchControl Search Control.
* @exception UMSException if failure.
* @exception InvalidSearchFilterException if failure.
*
* @supported.api
*/
public SearchResults searchIDs(
int scope,
) throws InvalidSearchFilterException, UMSException {
// TODO: support LDAP referral
}
/**
* Fetches the schema from the LDAP directory server. Retrieve the entire
* schema from the root of a Directory Server.
*
* @return the schema in the LDAP directory server
* @exception AccessRightsException
* insufficient access
* @exception UMSException
* Fail to fetch the schema.
* @exception LdapException
* Error with LDAP connection.
*
* @supported.api
*/
int retry = 0;
while (retry <= connNumRetry) {
if (debug.messageEnabled()) {
}
try {
} catch (LdapException e) {
throw e;
}
retry++;
try {
} catch (InterruptedException ex) {
}
}
}
} catch (LdapException e) {
throw new AccessRightsException(m_host, e);
} else {
throw new UMSException(m_host, e);
}
}
return null;
}
private synchronized void initReplicaProperties() {
if (retries < 0) {
retries = 0;
}
if (interval < 0) {
interval = 0;
}
}
int retry = 0;
int connRetry = 0;
if (debug.messageEnabled()) {
+ connRetry);
}
try {
} else {
}
} catch (LdapException e) {
if (debug.messageEnabled()) {
+ " retry: " + retry);
}
if (retry == replicaRetryNum) {
ldapEx = e;
} else {
try {
}
}
retry++;
if (connRetry == connNumRetry) {
ldapEx = e;
} else {
try {
}
}
connRetry++;
} else {
throw e;
}
}
}
throw ldapEx;
}
public ConnectionEntryReader readLDAPEntry(Principal principal, SearchRequest request) throws UMSException {
int retry = 0;
int connRetry = 0;
if (debug.messageEnabled()) {
+ connRetry);
}
} catch (LdapException e) {
if (debug.messageEnabled()) {
}
if (retry == replicaRetryNum) {
ldapEx = e;
} else {
try {
}
}
retry++;
if (connRetry == connNumRetry) {
ldapEx = e;
} else {
try {
}
}
connRetry++;
} else {
throw new UMSException(e.getMessage(), e);
}
}
}
}
/**
* Initialize the pool shared by all DataLayer object(s).
*/
private synchronized void initLdapPool() throws UMSException {
// Don't do anything if pool is already initialized
return;
/*
* Initialize the pool with minimum and maximum connections settings
* retrieved from configuration
*/
try {
} catch (LDAPServiceException ex) {
}
// Check if svrCfg was successfully obtained
}
m_releaseConnectionBeforeSearchCompletes = svrCfg.getBooleanValue(LDAP_RELEASECONNBEFORESEARCH, false);
if (debug.messageEnabled()) {
}
if (idleTimeout == 0) {
}
new ShutdownListener() {
public void shutdown() {
}
}
}
);
}
public static int getConnNumRetry() {
return connNumRetry;
}
public static int getConnRetryInterval() {
return connRetryInterval;
}
return retryErrorCodes;
}
private static void initializeEventService() {
// Initialize event service. This is to make sure that EventService
// thread is started. The other place where it is also tried to start
// is: com.iplanet.am.sdk.ldap.AMEventManager which is
// initialized in com.iplanet.am.sdk.ldap.DirectoryManager
if (!EventService.isStarted()) {
// Use a separate thread to start the EventService thread.
// This will prevent deadlocks associated in the system because
// of EventService related dependencies.
"InitEventServiceThread");
initEventServiceThread.setDaemon(true);
}
}
private static class InitEventServiceThread implements Runnable {
public void run() {
+ "EventService thread getting initialized ");
try {
synchronized (es) {
if (!EventService.isStarted()) {
}
}
} catch (Exception e) {
// An Error occurred while initializing EventService
}
}
}
private int m_port;
private boolean m_releaseConnectionBeforeSearchCompletes = false;
private class DataLayerConfigListener implements ConfigurationListener {
public synchronized void notifyChanges() {
}
}
}
}