⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dxattribute.java

📁 JAVA开源LDAP浏览器jxplorer的源码!
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
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 + -