📄 dxattribute.java
字号:
package com.ca.commons.naming;
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.text.CollationKey;
import java.text.Collator;
import com.ca.commons.cbutil.*;
import com.ca.commons.jndi.SchemaOps;
/**
* <p>This is a schema-aware wrapper to BasicAttribute<p>
*
* <p>It goes to a lot of effort to figure out whether the attribute has
* string values, or contains 'byte array' values. If it contains byte array values,
* it also tries to figure out whether they are ASN1 values. This is important, as we
* need to make sure that byte array values are passed correctly to JNDI, and in addition
* we need to make sure that ASN1 values are passed using ';binary'.</p>
*/
//There was Confusion here between non-string syntaxes, and 'Binary' syntaxes which in ldap means ASN.1. encoded.
//We have modified the class to use 'non string' (for byte arrays) and 'ASN1' (for ASN1 structures). All ASN1
//structures are 'non string', but attributes like jpeg photos and so on are byte arrays, but not ASN1 structures...
public class DXAttribute extends BasicAttribute implements Comparable
{
//protected boolean isNonString = false; // whether this attribute is isNonString data (e.g. ASN1 or a jpeg, an audio file etc.)
protected boolean isString = true; // whether this attribute is an ordinary string, or something else (e.g. ASN1 or a jpeg, an audio file etc.). Default is true (most attributes are strings).
protected boolean isASN1 = false;
static boolean appendBinaryOption = false; // whether to add ';binary' to the end of non String attribute names.
String name; // the name of the attribute (usually identical to the ID, unless ';binary' has been added to the ID)
String syntaxOID; // the OID of the Syntax (i.e. "1.3.6.1.4.1.1466.115.121.1.5" for binary)
String syntaxDesc; // the same thing as a human readable description
String description; // the free form description of the attribute that may exist in schema
private static final String STRING = "string";
private static final String BYTE_ARRAY = "bytes";
private static final String ASN1 = "asn1";
static Hashtable knownAttributeTypes; // a list of known 'attributes, matched against the constants above
static SchemaOps schema; // the schema of the most recently connected to directory
private CollationKey collationKey; // used for language-sensitive sorting.
private static Collator myCollator = Collator.getInstance(); // used for language-sensitive sorting.
private final static Logger log = Logger.getLogger(DXAttribute.class.getName()); // ...It's round it's heavy it's wood... It's better than bad, it's good...
static
{
knownAttributeTypes = new Hashtable(100);
}
/**
* Normal constructor for an Attribute with no (current) value.
* @param ID the name of the attribute (e.g. "userCertificate")
*/
public DXAttribute(String ID)
{
super(ID);
init();
}
/**
* Normal constructor an Attribute with a single value.
* @param ID the name of the attribute (e.g. "commonName")
* @param value the value of the attribute (String or byte array). e.g. "Fred"
*/
public DXAttribute(String ID, Object value)
{
super(ID, value);
init();
}
/**
* Make a copy of a normal, pre-existing attribute.
* @param att the attribute (e.g. BasicAttribute) to wrap.
*/
public DXAttribute(Attribute att)
{
super(att.getID());
try
{
addValues(att.getAll());
}
catch (NamingException e)
{
log.log(Level.WARNING, "error reading attribute values for attribute " + getID() + "\n", e);
}
setName(att.getID()); // ?? necessary??
init();
}
/**
* Creates an attribute with an enumeration of existing values.
* @param ID the name of the attribute (e.g. "favoriteDrink")
* @param values a set of values (e.g. "midori"... "cointreau"... "lemon juice"... "japanese slipper"
*/
public DXAttribute(String ID, NamingEnumeration values)
{
super(ID);
addValues(values);
init();
}
/**
* Adds a series of values to the attribute.
* @param values a bunch of new values to append to the attribute
*/
public void addValues(NamingEnumeration values)
{
try
{
while (values.hasMore())
{
add(values.next());
}
}
catch (NamingException e)
{
log.log(Level.WARNING, "error adding values for attribute " + getID(), e);
}
}
/**
* Attempts to sort the values of the attribute alphabetically. This is a
* relatively expensive operation, and should be used sparingly. (e.g. at GUI
* display time)
*/
public void sort()
{
if (values.size()<2)
return; // nothing to do.
try
{
// $%^# don't know how to write this to keep both java 1.4 & 1.5 happy - compiles under both, but 1.5 IDEs may flag this...
Collections.sort((List)values);
}
catch (ClassCastException e)
{
// nope, can't do that...
}
catch (UnsupportedOperationException e)
{
// nope, can't do that either...
}
}
/**
* This sets the standard schema to use while this connection is open.
* (It may be possible in future releases to set schema on a per-Attribute
* basis - it is not clear yet whether this would be useful.)
*/
public static void setDefaultSchema(SchemaOps defaultSchema)
{
schema = defaultSchema;
}
/**
* <p>Code common to all constructors, run at the *end* of each constructor.</p>
*/
protected void init()
{
// figure out whether this is a byte array, and whether it is an ASN1 structure
setAttributeType();
// used for sorting. XXX should this be delayed until we actually need to do any sorting??
collationKey = myCollator.getCollationKey(getID());
}
/**
* This method examines the schema to test whether the attribute is string, byte array or ASN1 data.
*/
protected void setAttributeType()
{
// quickly handle schema atts.
String ID = getID();
// skip 'synthetic' schemas
if ("SYNTAXNAMENUMERICOIDDESCEQUALITY".indexOf(ID) != -1) return;
ID = ID.toLowerCase();
// see if we've already cached details about this attribute ID
if (knownAttributeTypes.get(ID) != null)
{
isString = STRING.equals(knownAttributeTypes.get(ID));
isASN1 = ASN1.equals(knownAttributeTypes.get(ID));
}
// if the attribute ends with ;binary, then it must be both isNonString and ASN1
else if (ID.endsWith(";binary"))
{
isString = false;
isASN1 = true;
}
else if (schema != null)
{
setAttributeTypeFromSchema(); // sets isString and isASN1 variables
}
else // guessing time - we don't have a schema, but we'll try to figure it out from the value.
{
try
{
if (size() > 0)
{
Object value = get();
isString = (value == null || value instanceof String);
if (!isString)
isASN1 = isKnownASN1Attribute(ID); // more guessing...
}
}
catch (NamingException e)
{
log.log(Level.WARNING, "Unexpected error reading value from attribute " + ID, e);
}
}
updateTypesHashtable(ID);
}
private void updateTypesHashtable(String ID)
{
if (knownAttributeTypes.contains(ID) == false)
{
if (isString)
knownAttributeTypes.put(ID, STRING);
else if (isASN1)
knownAttributeTypes.put(ID, ASN1);
else
knownAttributeTypes.put(ID, BYTE_ARRAY);
}
}
/**
* Does this attribute have a valid value (i.e. not null, or empty string).
*/
public static boolean isEmpty(Attribute att)
{
if (att == null || att.size() == 0)
{
return true;
}
else if (att.size() == 1)
{
Object val = null;
try
{
val = att.get();
}
catch (NamingException e)
{
return true; // assume naming exception means empty attribute... (?)
}
if (val == null || "".equals(val))
return true;
}
return false;
}
/**
* This returns whether the Syntax is a non string syntax that should be passed
* via a byte array in JNDI
*
* @param syntaxName
* @return
*/
public static boolean isStringSyntax(String syntaxName)
{
if (syntaxName == null)
return true; //don't know - default to 'yes'
int pos = syntaxName.indexOf("1.3.6.1.4.1.1466.115.121.1.");
if (pos == -1)
return true; //don't know - default to 'yes'
// some faffing around to get the final number of the OID. Could probably be neatened up :-).
String number = syntaxName.substring(pos + "1.3.6.1.4.1.1466.115.121.1.".length());
if (number.length() > 2)
{
number = number.substring(0, 2);
char c = number.charAt(1);
if (Character.isDigit(c) == false)
number = number.substring(0, 1);
}
try
{
int finalNumber = Integer.parseInt(number);
switch (finalNumber)
{
case 4:
return false; // 1.3.6.1.4.1.1466.115.121.1.4 - audio
case 5:
return false; // 1.3.6.1.4.1.1466.115.121.1.5 - ASN1 binary
case 8:
return false; // 1.3.6.1.4.1.1466.115.121.1.8 - certificate
case 9:
return false; // 1.3.6.1.4.1.1466.115.121.1.9 - certificate list
case 10:
return false; // 1.3.6.1.4.1.1466.115.121.1.10 - certificate pair
case 28:
return false; // 1.3.6.1.4.1.1466.115.121.1.28 - jpeg
case 40:
return false; // 1.3.6.1.4.1.1466.115.121.1.40 - octet string
default:
return true;
}
}
catch (NumberFormatException e)
{
log.log(Level.WARNING, "Unexpected error parsing syntax: " + syntaxName, e);
return true;
}
}
/**
* Returns whether the attribute is an ASN.1 structure
* (and thus a candidate for having ;binary tacked on to its name)
*
* @param syntaxName the name of the syntax (usually a thumping great OID)
* @return
*/
public static boolean isASN1Syntax(String syntaxName)
{
if (syntaxName == null)
return false;
int pos = syntaxName.indexOf("1.3.6.1.4.1.1466.115.121.1.");
if (pos == -1)
return false;
String number = syntaxName.substring(pos + "1.3.6.1.4.1.1466.115.121.1.".length());
if (number.length() > 2)
{
number = number.substring(0, 2);
char c = number.charAt(1);
if (Character.isDigit(c) == false)
number = number.substring(0, 1);
}
try
{
int finalNumber = Integer.parseInt(number);
switch (finalNumber)
{
case 5:
return true; // 1.3.6.1.4.1.1466.115.121.1.5 - ASN1 binary
case 8:
return true; // 1.3.6.1.4.1.1466.115.121.1.8 - certificate
case 9:
return true; // 1.3.6.1.4.1.1466.115.121.1.9 - certificate list
case 10:
return true; // 1.3.6.1.4.1.1466.115.121.1.10 - certificate pair
default:
return false;
}
}
catch (NumberFormatException e)
{
log.log(Level.WARNING, "Unexpected error parsing syntax: " + syntaxName, e);
return false;
}
}
/**
* <p>Look up the attribute ID in the schema, and see whether the
* syntax found there is a String, or if it is a byte array whether it is also an ASN1 structure.</p>
* <p>This method sets the following globals:</p>
* syntaxOID<br>
* isString<br>
* isASN1<br>
*/
public void setAttributeTypeFromSchema()
{
if (schema != null)
{
try
{
String attributeNameInSchema = "AttributeDefinition/" + getID();
Attributes atts = schema.getAttributes(attributeNameInSchema);
Attribute syntaxAttribute = null;
while (atts!=null && (syntaxAttribute = atts.get("SUP")) != null)
{
atts = schema.getAttributes("AttributeDefinition/" + syntaxAttribute.get().toString());
}
if (atts!=null)
syntaxAttribute = atts.get("SYNTAX");
if (syntaxAttribute != null)
{
syntaxOID = syntaxAttribute.toString();
isString = isStringSyntax(syntaxOID);
if (!isString)
isASN1 = isASN1Syntax(syntaxOID);
}
else
{
log.info(" Can't find SYNTAX for... " + getID());
}
}
// XXX does this actually work on any known ldap server??
// XXX - if so, should modify above so that when atts == null the below is run I guess...
catch (NamingException e) // usually means the attribute wasn't found under that name. Try again using ';binary' suffix.
{
try
{
Attributes atts = schema.getAttributes("AttributeDefinition/" + getID() + ";binary");
// if we find anything at all, it must be an ASN1 ;binary attribute...
if (atts != null)
{
isString = false;
isASN1 = true;
}
}
catch (Exception e2) // give up
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -