📄 jndibroker.java
字号:
package com.ca.directory.jxplorer.broker;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.*;
import com.ca.directory.jxplorer.*;
import com.ca.commons.naming.*;
import com.ca.commons.cbutil.*;
import com.ca.commons.jndi.*;
/**
* This utility class handles all the JNDIBroker LDAP calls, returning objects
* to calling classes and managing the connection.<p>
*
* Before examining this class make sure to examing the base Broker class thoroughly.
* The base Broker class takes user requests, and creates DataQuery objects. A
* separate thread takes these DataQuery objects and uses the methods of derived
* classes (such as this one) to do the actual grunt work.
*/
public class JNDIBroker extends Broker
{
// private static final String DEFAULT_CTX = "com.sun.jndi.ldap.LdapCtxFactory";
private static final int SEARCHLIMIT = 0;
private static final int SEARCHTIMEOUT = 0;
/**
* Used as a parameter to unthreadedSearch, this specifies to only search
* the base object.
*/
public static final int SEARCH_BASE_OBJECT = 0;
/**
* Used as a parameter to unthreadedSearch, this specifies to only search
* the next level from the current DN.
*/
public static final int SEARCH_ONE_LEVEL = 1;
/**
* Used as a parameter to unthreadedSearch, this specifies to search
* the entire subtree from the current DN.
*/
public static final int SEARCH_SUB_TREE = 2;
private DirContext ctx;
// private DirContext schemactx;
// private Attributes schemaOps;
private boolean tracing = false;
private boolean connectionError = true;
private Hashtable attributeNames;
private boolean quietMode = false; // suppress gui ops (esp. error msgs.)
private boolean errorWhileQuietFlag = false; // used when broker is in 'quiet gui mode'.
int limit = SEARCHLIMIT; // default number of results returned.
int timeout = SEARCHTIMEOUT; // default timeout.
static int threadID = 1; // debug identifier for thread tracking
static final boolean DEBUGTHREADS = false; // debug flag for threadiness
private CBGraphicsOps dirOps = null; // the low level directory operations class.
private SchemaOps schemaOps; // the low level schemaOps class
private HashSet specialObjectClasses; // OS390 hack
private final static Logger log = Logger.getLogger(JNDIBroker.class.getName());
/**
* Helper class for Broker, this encapsulates an ldap-like connection
* request that is placed on the Broker queue for eventual resolution.
* The Connection Request object is intended to be used once, and then
* discarded.
*/
public class DataConnectionQuery extends DataQuery
{
public final ConnectionData conData;
/**
* Defines a request to open a connection to an LDAP (only) server.
* @param cData a data object containing connection information.
*/
public DataConnectionQuery(ConnectionData cData)
{
super(DataQuery.EXTENDED);
conData = cData;
setExtendedData("version", String.valueOf(conData.version));
setExtendedData("url", conData.getURL());
}
/**
* Utility name translation method
*/
public String getTypeString()
{
return super.getTypeString() + " Connection Request";
}
}
/**
* Constructor does nothing except create an env object ( 'connect()'
* is used to open a connection)
*/
public JNDIBroker()
{
initSpecialObjectClasses();
}
/**
* Clones a JNDIBroker, using the same underlying directory connection,
* but clearing the data listener list, and having its own debug flags.
* Any StopMonitors however will need to be re-registered with the new
* Broker.
* @param cloneMe
*/
public JNDIBroker(JNDIBroker cloneMe)
{
registerDirectoryConnection(cloneMe);
}
/**
* Resets a JNDIBroker, using the same underlying directory connection
* as the passed broker, but clearing the data listener list, and resetting debug flags.
* Any StopMonitors however will need to be re-registered.
* @param cloneMe
*/
public void registerDirectoryConnection(JNDIBroker cloneMe)
{
ctx = cloneMe.ctx;
// schemaOps = cloneMe.schemaOps;
tracing = cloneMe.tracing;
connectionError = cloneMe.connectionError;
attributeNames = cloneMe.attributeNames;
limit = cloneMe.limit;
timeout = cloneMe.timeout;
dirOps = cloneMe.dirOps;
schemaOps = cloneMe.schemaOps;
specialObjectClasses = cloneMe.specialObjectClasses; // OS390 hack
}
/**
* Mitch/OS390 hack
*/
protected void initSpecialObjectClasses()
{
String fileName = System.getProperty("user.dir") + File.separator + "specialocs.txt";
if (new File(fileName).exists())
{
try
{
String text = CBUtility.readTextFile(new File(fileName));
StringTokenizer st = new StringTokenizer(text);
specialObjectClasses = new HashSet(10);
while (st.hasMoreTokens())
{
String oc = st.nextToken();
specialObjectClasses.add(oc);
}
}
catch (Exception e)
{
log.info("unable to obtain special object classes list:\n " + e.toString());
specialObjectClasses = null;
}
}
}
/**
* Suppresses user notification of errors via GUI dialogs,
* and logs them instead. Necessary for large batch ops. like
* importing an ldif file.
* @param status
*/
public void setGUIQuiet(boolean status)
{
quietMode = status;
dirOps.setQuietMode(status);
if (quietMode == false)
setQuietError(false); // clear quiet error flag.
}
/**
* Sets the quiet error flag status.
* @param status
*/
public void setQuietError(boolean status)
{
errorWhileQuietFlag = status;
}
/**
* This returns whether one or more errors occured while the
* program was in 'quiet gui' (i.e. no error dialogs) mode.
* It does not return the actual error, since frequently there
* were many: the user should consult the log file.
* @return
*/
public boolean getQuietError()
{
return (errorWhileQuietFlag || dirOps.errorWhileQuietFlag);
}
/**
* Sets ber tracing status. Set to true this generates a huge
* amount of comms. tracing info, <i>when the next connection is opened</i>.
* It doesn't seem possible to set it for an already open connection, so
* we no longer even try.
* @param traceStatus
*/
public void setTracing(boolean traceStatus)
{
tracing = traceStatus;
}
/**
* Returns ber tracing status. When true this generates a huge
* amount of comms. tracing info, <i>when the next connection is opened</i>.
* It doesn't seem possible to set it for an already open connection, so
* we no longer even try.
* @return the traceStatus
*/
public boolean getTracing() { return tracing; }
/**
* <p>Queues a request to open a connection to an LDAP (only) server.</p>
*
* <p>Note that some rarely modified connection status variables are set externally - e.g.
* BER tracing status (derived from the log level, set by setTracing() ),
* and the security keystore type and external security provider (if any)
* which are set in the config file).</p>
*
* @param baseDN the base DN from which to browse.
* @param version the LDAP Version (2 or 3) being used.
* @param host the LDAP server url.
* @param port the LDAP server port (default 389) being used.
* @param userDN the Manager User's DN - (is null if user is not manager)
* @param pwd the Manager User's password - (is null if user is not manager)
* @param referralType the jndi ldap referral type: [follow:ignore:throw]
* @param aliasType how aliases are handled: 'always'|'never'|'finding'|'searching'
* @param useSSL whether to use SSL for encryption and/or authentication (dependant on other parameters)
* @param cacerts path to a store of trusted server certificates or CA certificates - required for Server-auth ssl
* @param clientcerts path to client certificates - if available, will use for client authentication
* @param caKeystorePwd the password to the client's keystore (may be null for non-client authenticated ssl).
* @param clientKeystorePwd the password to the client certificates - required to use client certs for authentication
* @deprecated use connect(ConnectionData) instead.
* @return returns the thread that is used to make the connection
*/
// nb capitalisation of 'cacerts' and 'clientcerts' wierd to match actual default file names.
public DataQuery connect(String baseDN, int version, String host,
int port, String userDN, char[] pwd,
String referralType, String aliasType, boolean useSSL,
String cacerts, String clientcerts,
char[] caKeystorePwd, char[] clientKeystorePwd)
{
ConnectionData cData = new ConnectionData();
cData.setURL(host,port);
cData.baseDN = baseDN;
cData.version = version;
cData.setURL(host, port);
cData.userDN = userDN;
cData.pwd = pwd;
cData.referralType = referralType;
cData.aliasType = aliasType;
cData.useSSL = useSSL;
cData.cacerts = cacerts;
cData.clientcerts = clientcerts;
cData.caKeystorePwd = caKeystorePwd;
cData.clientKeystorePwd = clientKeystorePwd;
cData.tracing = getTracing();
return connect(cData);
}
/**
* <p>Queues a request to open a connection to an LDAP (only) server.</p>
*
* <p>Note that some rarely modified connection status variables are set externally - e.g.
* BER tracing status (derived from the log level, set by setTracing() ),
* and the security keystore type and external security provider (if any)
* which are set in the config file).</p>
* @param cData data object containing all the connection information.
* @return returns the thread that is used to make the connection
*/
public DataQuery connect(ConnectionData cData)
{
cData.caKeystoreType = JXplorer.getProperty("keystoreType.cacerts", "JKS");
cData.clientKeystoreType = JXplorer.getProperty("keystoreType.clientcerts", "JKS");
DataQuery openCon = new DataConnectionQuery(cData);
return push(openCon);
}
/**
* Extends the base class processRequest method to handle DataConnectionRequest objects.
* @param request the connection data query.
*/
protected void processRequest(DataQuery request)
{
try
{
if (request instanceof DataConnectionQuery)
openConnection((DataConnectionQuery) request);
else
super.processRequest(request);
}
catch (Exception e)
{
request.setException(e);
e.printStackTrace();
}
}
/**
* Does the actual grunt work of opening a new connection.
* @param request a DataQuery object that contains the connection details.
* @return the data query object.
*/
protected DataQuery openConnection(DataConnectionQuery request)
{
disconnect(); // clear out any existing cobwebs...
ConnectionData cData = request.conData;
String url = cData.url;
connectionError = false;
ctx = null; // null the current directory context (can't be used again).
// Try to get a directory context using above info.
try
{
dirOps = new CBGraphicsOps(cData); // this wraps up ctx for basic operations
ctx = dirOps.getContext();
if (ctx == null)
throw new NamingException("unable to open connection: unknown condition, no error returned.");
// make a bogus, fast, directory request to trigger some activity on the context. Without this the
// context may *appear* to be open since jndi sometimes won't actually try to use it until a request is made
// (e.g. with DSML, SSL connections etc.)
String base = (request.conData.baseDN==null)?"":request.conData.baseDN;
//XXX bogus request failing - why??? (ans SASL error in jdk 1.4.0 - 1.4.1)
//ctx.search(base, "objectClass=*", new SearchControls(SearchControls.OBJECT_SCOPE, 0, 0, new String[]{}, false, false));
if (dirOps.exists(base) == false)
cData.baseDN = getActualDN(cData.baseDN); //TE: (for bug 2363) - try to solve case sensitive DN problem.
// At this stage we should have a valid ldap context
}
// can throw NamingException, GeneralSecurityException, IOException
catch (Exception ne) // An error has occurred. Exit connection routine
{ // taking no further action.
log.warning("initial receipt of exception by jndi broker " + ne.getMessage());
ne.printStackTrace();
request.setException(ne);
request.setStatus(false);
request.finish();
return request;
}
try
{
schemaOps = new SchemaOps(ctx);
} // this wraps up ctx for basic operations
catch (NamingException e)
{
log.log(Level.WARNING, "unable to init schemaOps Ops ", e);
schemaOps = null;
}
if (schemaOps != null && (cData.protocol == ConnectionData.DSML || cData.version > 2)) // if ldap 3 or better try to open a schemaOps context
{
try
{
String binaries = schemaOps.getNewBinaryAttributes();
if (binaries.trim() != "")
ctx.addToEnvironment("java.naming.ldap.attributes.binary", binaries);
initAttributeNamesHash();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -