📄 dsmlcontext.java
字号:
package com.ca.jndiproviders.dsml;
import com.ca.commons.naming.DXNamingEnumeration;
import com.ca.commons.naming.DN;
import com.ca.commons.cbutil.CBBase64;
import com.ca.commons.cbutil.CBBase64EncodingException;
import javax.naming.directory.*;
import javax.naming.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
/**
* <p>This is a DSML jndiproviders context, that provides support for all the basic DSML operations.</p>
* <p/>
* <p>However, it deliberately does *not* support:</p>
* <ul>
* <li>binding java objects - the bind methods are not implemented. Users will need to do their
* own serialisation if they want this functionality.
* <li> referrals aren't implemented yet.
* <li> ldap v3 extensions.
* <li> composite names spanning multiple namespaces - all names are DSML names only. (Composite
* names are a bloody stupid idea that come close to making jndiproviders unusable, IMNSHO - CB)
* </ul>
* <p/>
* <p>If you need the above features, you may be better off using the Sun DSML provider which is
* far more ambitious in scope (but which has some licencing problems, and is a bit rocky in parts).</p>
*/
/*
* DSML SERVER ERROR NOTES
*
* Server is incorrectly parsing escaped dns - e.g. dn="cn=Vivienne \"LEVER\", ... ".
* Server is returning HTTP 500, which prevents parsing of returned soap error
*
*/
//TODO: schema support??
//TODO: we ended up using strings rather than names, so adjust all methods to chain to the string methods instead of the name methods.
//TODO: makes heavy use of static stuff - may not be thread safe.
public class DsmlContext implements DirContext
{
// Formatting
private static int TABLEN = 4;
private static String TAB = " ";
private static String TAB2 = TAB + TAB;
private static String TAB3 = TAB2 + TAB;
private static String TAB4 = TAB3 + TAB;
private static String TAB5 = TAB4 + TAB;
private static String TAB6 = TAB5 + TAB;
private static String SOAPHEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
TAB + "<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
TAB2 + "<soap-env:Body>\n";
private static String SOAPFOOTER = TAB2 + "</soap-env:Body>\n" +
TAB + "</soap-env:Envelope>";
private static String DSMLHEADER = TAB3 + "<dsml:batchRequest xmlns:dsml=\"urn:oasis:names:tc:DSML:2:0:core\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n";
private static String DSMLFOOTER = TAB3 + "</dsml:batchRequest>\n";
private static String SEARCHFOOTER = TAB3 + "</dsml:searchRequest>\n";
private static String STANDARDHEADER = SOAPHEADER + DSMLHEADER;
private static String STANDARDFOOTER = DSMLFOOTER + SOAPFOOTER;
// SEARCH SCOPE CONSTANTS
private static String BASEOBJECT = "baseObject";
private static String SINGLELEVEL = "singleLevel";
private static String WHOLESUBTREE = "wholeSubtree";
private static String[] SCOPEOPTIONS = new String[]{BASEOBJECT, SINGLELEVEL, WHOLESUBTREE};
// SEARCH ALIAS DEREF OPTIONS
private static String NEVER = "neverDerefAliases";
private static String SEARCHING = "derefInSearching";
private static String FINDING = "derefFindingBaseObj";
private static String ALWAYS = "derefAlways";
private static String[] ALIASOPTIONS = new String[]{NEVER, SEARCHING, FINDING, ALWAYS};
// Default Search Controls
private static SearchControls DEFAULT_SEARCH_CONTROLS = new SearchControls();
protected Hashtable environment;
// the name of the context (as set by 'createSubcontext' methods
private String contextName = "";
private static Logger log = Logger.getLogger(DsmlContext.class.getName());
// Debug
{
log.setLevel(Level.FINEST);
}
/**
* <p>This constructs the XML tag and tag attributes for a DSML search operation start tag. (filter and attributes elements
* must be added separately, the end tag is a defined constant.)
* <p/>
* <p>e.g.
* <pre>
* <dsml:searchRequest requestID="1" dn="cn=schema" scope="baseObject" derefAliases="derefInSearching">
* </pre>
* <p/>
* something like
*
* @param searchHeader an existing string buffer to append the search header information in.
* @param dn the dn to search from
* @param scope the search scope, must be one of 'baseLevel', 'singleLevel' or 'wholeSubtree' (see constants)
* @param derefAliases how to handle aliases. must be on of 'neverDerefAliases', 'derefInSearching', 'derefFindingBaseObj', 'derefAlways' (see constants)
* @param sizeLimit the LDAP search size limit - default is 0 (unlimited by client)
* @param timeLimit the LDAP search time limit - default is 0 (unlimited by client)
* @param typesOnly - no idea, but it's in the spec.
* @return a string buffer containing the raw xml for a search operation.
* @throws NamingException
*/
private static StringBuffer getSearchRequestHeader(StringBuffer searchHeader, String dn, String scope, String derefAliases, long sizeLimit, int timeLimit, boolean typesOnly)
throws NamingException
{
// sanity check arguments
if (!checkValidity(SCOPEOPTIONS, scope))
throw new NamingException("search scope argument '" + scope + "' is invalid");
if (!checkValidity(ALIASOPTIONS, derefAliases))
{
if (derefAliases != null) log.info("bad alias option passed '" + derefAliases + "'");
derefAliases = SEARCHING;
}
if (searchHeader == null)
searchHeader = new StringBuffer();
searchHeader.append(TAB4 + "<dsml:searchRequest dn=\""); // TODO: requestID is optional - let's drop it in the final version - CB
searchHeader.append(escapeName(dn));
searchHeader.append("\" scope=\"").append(scope);
searchHeader.append("\" derefAliases=\"").append(derefAliases);
if (sizeLimit > 0)
searchHeader.append("\" sizeLimit=\"").append(sizeLimit);
if (timeLimit > 0)
searchHeader.append("\" timeLimit=\"").append(timeLimit);
// never used?
if (typesOnly == true)
searchHeader.append("\" typesOnly=\"").append(typesOnly);
searchHeader.append("\">\n");
log.finest("created search header: " + searchHeader);
return searchHeader;
}
/**
* <p>This constructs the XML tag and elements for a DSML search attribute list
* <p/>
* e.g.
* <pre>
* >dsml:attributes<
* >dsml:attribute name="attributeTypes"/<
* >dsml:attribute name="objectClasses"/<
* >dsml:attribute name="matchingRules"/<
* >dsml:attribute name="ldapSyntaxes"/<
* >dsml:attribute name="*"/<
* >/dsml:attributes<
* </pre>
*
* @param searchAttributes an existing string buffer to append the search attribute list information to
* @param attributes a string array of attribute names
* @return
*/
private static StringBuffer getSearchRequestAttributes(StringBuffer searchAttributes, String[] attributes)
{
if (attributes == null || attributes.length == 0)
{
return searchAttributes; // do nothing if there are no specific attributes (means return all)
}
if (searchAttributes == null)
searchAttributes = new StringBuffer(40 + 80 * attributes.length);
searchAttributes.append(TAB5 + "<dsml:attributes>\n");
int len = attributes.length;
for (int i = 0; i < len; i++)
{
searchAttributes.append(TAB6 + "<dsml:attribute name=\"").append(attributes[i]).append("\"/>\n");
}
searchAttributes.append(TAB5 + "</dsml:attributes>\n");
log.finest("created search attribute list: " + searchAttributes);
return searchAttributes;
}
/**
* Small utility method to check that a string is one of a number of valid options.
*
* @param options an array of valid options.
* @param checkme a string to compare against the previous array.
* @return true if checkme is one of the options, false if it is null, or is not one of the options.
*/
private static boolean checkValidity(String[] options, String checkme)
{
if (checkme != null)
{
for (int i = 0; i < options.length; i++)
if (options[i].equals(checkme))
return true;
}
return false;
}
/**
* A little test method to produce dummy enumerations during development
*
* @param name
* @param num
* @return
*/
private NamingEnumeration getTestEnumeration(Name name, int num)
{
log.finest("generating " + num + " test names from '" + name.toString() + "'");
String itemBase = "c=AU";
if (name.size() == 1)
itemBase = "o=beta";
else if (name.size() == 2)
itemBase = "ou=gamma";
else if (name.size() == 3)
itemBase = "ou=delta";
DXNamingEnumeration testEnumeration = new DXNamingEnumeration();
for (int i = 0; i < num; i++)
{
String itemName = itemBase + i;
testEnumeration.add(new SearchResult(itemName, null, getTestAttributes(itemName)));
}
return testEnumeration;
}
/**
* A little test method to produce dummy attributes objects during development.
*
* @param name
* @return
*/
private BasicAttributes getTestAttributes(String name)
{
log.finest("generating test data from name '" + name + "'");
BasicAttributes testAttributes = new BasicAttributes("cn", name);
testAttributes.put(new BasicAttribute("objectClass", "person"));
testAttributes.put(new BasicAttribute("sn", "Test"));
return testAttributes;
}
private DsmlContext()
{
} // don't do this :-).
private DsmlContext(String baseDN, Hashtable env)
{
contextName = baseDN==null?"":baseDN;
environment = env; // Don't see any reason to clone environment for every entry?
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -