/* * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.naming.directory;import java.util.Hashtable;import java.util.Enumeration;import javax.naming.NamingException;import javax.naming.NamingEnumeration;/** * This class provides a basic implementation * of the Attributes interface. *<p> * BasicAttributes is either case-sensitive or case-insensitive (case-ignore). * This property is determined at the time the BasicAttributes constructor * is called. * In a case-insensitive BasicAttributes, the case of its attribute identifiers * is ignored when searching for an attribute, or adding attributes. * In a case-sensitive BasicAttributes, the case is significant. *<p> * When the BasicAttributes class needs to create an Attribute, it * uses BasicAttribute. There is no other dependency on BasicAttribute. *<p> * Note that updates to BasicAttributes (such as adding or removing an attribute) * does not affect the corresponding representation in the directory. * Updates to the directory can only be effected * using operations in the DirContext interface. *<p> * A BasicAttributes instance is not synchronized against concurrent * multithreaded access. Multiple threads trying to access and modify * a single BasicAttributes instance should lock the object. * * @author Rosanna Lee * @author Scott Seligman * * @see DirContext#getAttributes * @see DirContext#modifyAttributes * @see DirContext#bind * @see DirContext#rebind * @see DirContext#createSubcontext * @see DirContext#search * @since 1.3 */public class BasicAttributes implements Attributes { /** * Indicates whether case of attribute ids is ignored. * @serial */ private boolean ignoreCase = false; // The 'key' in attrs is stored in the 'right case'. // If ignoreCase is true, key is aways lowercase. // If ignoreCase is false, key is stored as supplied by put(). // %%% Not declared "private" due to bug 4064984. transient Hashtable attrs = new Hashtable(11); /** * Constructs a new instance of Attributes. * The character case of attribute identifiers * is significant when subsequently retrieving or adding attributes. */ public BasicAttributes() { } /** * Constructs a new instance of Attributes. * If <code>ignoreCase</code> is true, the character case of attribute * identifiers is ignored; otherwise the case is significant. * @param ignoreCase true means this attribute set will ignore * the case of its attribute identifiers * when retrieving or adding attributes; * false means case is respected. */ public BasicAttributes(boolean ignoreCase) { this.ignoreCase = ignoreCase; } /** * Constructs a new instance of Attributes with one attribute. * The attribute specified by attrID and val are added to the newly * created attribute. * The character case of attribute identifiers * is significant when subsequently retrieving or adding attributes. * @param attrID non-null The id of the attribute to add. * @param val The value of the attribute to add. If null, a null * value is added to the attribute. */ public BasicAttributes(String attrID, Object val) { this(); this.put(new BasicAttribute(attrID, val)); } /** * Constructs a new instance of Attributes with one attribute. * The attribute specified by attrID and val are added to the newly * created attribute. * If <code>ignoreCase</code> is true, the character case of attribute * identifiers is ignored; otherwise the case is significant. * @param attrID non-null The id of the attribute to add. * If this attribute set ignores the character * case of its attribute ids, the case of attrID * is ignored. * @param val The value of the attribute to add. If null, a null * value is added to the attribute. * @param ignoreCase true means this attribute set will ignore * the case of its attribute identifiers * when retrieving or adding attributes; * false means case is respected. */ public BasicAttributes(String attrID, Object val, boolean ignoreCase) { this(ignoreCase); this.put(new BasicAttribute(attrID, val)); } public Object clone() { BasicAttributes attrset; try { attrset = (BasicAttributes)super.clone(); } catch (CloneNotSupportedException e) { attrset = new BasicAttributes(ignoreCase); } attrset.attrs = (Hashtable)attrs.clone(); return attrset; } public boolean isCaseIgnored() { return ignoreCase; } public int size() { return attrs.size(); } public Attribute get(String attrID) { Attribute attr = (Attribute) attrs.get( ignoreCase ? attrID.toLowerCase() : attrID); return (attr); } public NamingEnumeration<Attribute> getAll() { return new AttrEnumImpl(); } public NamingEnumeration<String> getIDs() { return new IDEnumImpl(); } public Attribute put(String attrID, Object val) { return this.put(new BasicAttribute(attrID, val)); } public Attribute put(Attribute attr) { String id = attr.getID(); if (ignoreCase) { id = id.toLowerCase(); } return (Attribute)attrs.put(id, attr); } public Attribute remove(String attrID) { String id = (ignoreCase ? attrID.toLowerCase() : attrID); return (Attribute)attrs.remove(id); } /** * Generates the string representation of this attribute set. * The string consists of each attribute identifier and the contents * of each attribute. The contents of this string is useful * for debugging and is not meant to be interpreted programmatically. * * @return A non-null string listing the contents of this attribute set. */ public String toString() { if (attrs.size() == 0) { return("No attributes"); } else { return attrs.toString(); } } /** * Determines whether this <tt>BasicAttributes</tt> is equal to another * <tt>Attributes</tt> * Two <tt>Attributes</tt> are equal if they are both instances of * <tt>Attributes</tt>, * treat the case of attribute IDs the same way, and contain the * same attributes. Each <tt>Attribute</tt> in this <tt>BasicAttributes</tt> * is checked for equality using <tt>Object.equals()</tt>, which may have * be overridden by implementations of <tt>Attribute</tt>). * If a subclass overrides <tt>equals()</tt>, * it should override <tt>hashCode()</tt> * as well so that two <tt>Attributes</tt> instances that are equal * have the same hash code. * @param obj the possibly null object to compare against. * * @return true If obj is equal to this BasicAttributes. * @see #hashCode */ public boolean equals(Object obj) { if ((obj != null) && (obj instanceof Attributes)) { Attributes target = (Attributes)obj; // Check case first if (ignoreCase != target.isCaseIgnored()) { return false; } if (size() == target.size()) { Attribute their, mine; try { NamingEnumeration theirs = target.getAll(); while (theirs.hasMore()) { their = (Attribute)theirs.next(); mine = get(their.getID()); if (!their.equals(mine)) { return false; } } } catch (NamingException e) { return false; } return true; } } return false; } /** * Calculates the hash code of this BasicAttributes. *<p> * The hash code is computed by adding the hash code of * the attributes of this object. If this BasicAttributes * ignores case of its attribute IDs, one is added to the hash code. * If a subclass overrides <tt>hashCode()</tt>, * it should override <tt>equals()</tt> * as well so that two <tt>Attributes</tt> instances that are equal * have the same hash code. * * @return an int representing the hash code of this BasicAttributes instance. * @see #equals */ public int hashCode() { int hash = (ignoreCase ? 1 : 0); try { NamingEnumeration all = getAll(); while (all.hasMore()) { hash += all.next().hashCode(); } } catch (NamingException e) {} return hash; } /** * Overridden to avoid exposing implementation details. * @serialData Default field (ignoreCase flag -- a boolean), followed by * the number of attributes in the set * (an int), and then the individual Attribute objects. */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); // write out the ignoreCase flag s.writeInt(attrs.size()); Enumeration attrEnum = attrs.elements(); while (attrEnum.hasMoreElements()) { s.writeObject(attrEnum.nextElement()); } } /** * Overridden to avoid exposing implementation details. */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); // read in the ignoreCase flag int n = s.readInt(); // number of attributes attrs = (n >= 1) ? new Hashtable(n * 2) : new Hashtable(2); // can't have initial size of 0 (grrr...) while (--n >= 0) { put((Attribute)s.readObject()); } }class AttrEnumImpl implements NamingEnumeration<Attribute> { Enumeration<Attribute> elements; public AttrEnumImpl() { this.elements = attrs.elements(); } public boolean hasMoreElements() { return elements.hasMoreElements(); } public Attribute nextElement() { return elements.nextElement(); } public boolean hasMore() throws NamingException { return hasMoreElements(); } public Attribute next() throws NamingException { return nextElement(); } public void close() throws NamingException { elements = null; }}class IDEnumImpl implements NamingEnumeration<String> { Enumeration<Attribute> elements; public IDEnumImpl() { // Walking through the elements, rather than the keys, gives // us attribute IDs that have not been converted to lowercase. this.elements = attrs.elements(); } public boolean hasMoreElements() { return elements.hasMoreElements(); } public String nextElement() { Attribute attr = elements.nextElement(); return attr.getID(); } public boolean hasMore() throws NamingException { return hasMoreElements(); } public String next() throws NamingException { return nextElement(); } public void close() throws NamingException { elements = null; }} /** * Use serialVersionUID from JNDI 1.1.1 for interoperability. */ private static final long serialVersionUID = 4980164073184639448L;}
/*
* Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.naming.directory;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
/**
* This class provides a basic implementation
* of the Attributes interface.
*<p>
* BasicAttributes is either case-sensitive or case-insensitive (case-ignore).
* This property is determined at the time the BasicAttributes constructor
* is called.
* In a case-insensitive BasicAttributes, the case of its attribute identifiers
* is ignored when searching for an attribute, or adding attributes.
* In a case-sensitive BasicAttributes, the case is significant.
*<p>
* When the BasicAttributes class needs to create an Attribute, it
* uses BasicAttribute. There is no other dependency on BasicAttribute.
*<p>
* Note that updates to BasicAttributes (such as adding or removing an attribute)
* does not affect the corresponding representation in the directory.
* Updates to the directory can only be effected
* using operations in the DirContext interface.
*<p>
* A BasicAttributes instance is not synchronized against concurrent
* multithreaded access. Multiple threads trying to access and modify
* a single BasicAttributes instance should lock the object.
*
* @author Rosanna Lee
* @author Scott Seligman
*
* @see DirContext#getAttributes
* @see DirContext#modifyAttributes
* @see DirContext#bind
* @see DirContext#rebind
* @see DirContext#createSubcontext
* @see DirContext#search
* @since 1.3
*/
public class BasicAttributes implements Attributes {
/**
* Indicates whether case of attribute ids is ignored.
* @serial
*/
private boolean ignoreCase = false;
// The 'key' in attrs is stored in the 'right case'.
// If ignoreCase is true, key is aways lowercase.
// If ignoreCase is false, key is stored as supplied by put().
// %%% Not declared "private" due to bug 4064984.
transient Hashtable attrs = new Hashtable(11);
/**
* Constructs a new instance of Attributes.
* The character case of attribute identifiers
* is significant when subsequently retrieving or adding attributes.
*/
public BasicAttributes() {
}
/**
* Constructs a new instance of Attributes.
* If <code>ignoreCase</code> is true, the character case of attribute
* identifiers is ignored; otherwise the case is significant.
* @param ignoreCase true means this attribute set will ignore
* the case of its attribute identifiers
* when retrieving or adding attributes;
* false means case is respected.
*/
public BasicAttributes(boolean ignoreCase) {
this.ignoreCase = ignoreCase;
}
/**
* Constructs a new instance of Attributes with one attribute.
* The attribute specified by attrID and val are added to the newly
* created attribute.
* The character case of attribute identifiers
* is significant when subsequently retrieving or adding attributes.
* @param attrID non-null The id of the attribute to add.
* @param val The value of the attribute to add. If null, a null
* value is added to the attribute.
*/
public BasicAttributes(String attrID, Object val) {
this();
this.put(new BasicAttribute(attrID, val));
}
/**
* Constructs a new instance of Attributes with one attribute.
* The attribute specified by attrID and val are added to the newly
* created attribute.
* If <code>ignoreCase</code> is true, the character case of attribute
* identifiers is ignored; otherwise the case is significant.
* @param attrID non-null The id of the attribute to add.
* If this attribute set ignores the character
* case of its attribute ids, the case of attrID
* is ignored.
* @param val The value of the attribute to add. If null, a null
* value is added to the attribute.
* @param ignoreCase true means this attribute set will ignore
* the case of its attribute identifiers
* when retrieving or adding attributes;
* false means case is respected.
*/
public BasicAttributes(String attrID, Object val, boolean ignoreCase) {
this(ignoreCase);
this.put(new BasicAttribute(attrID, val));
}
public Object clone() {
BasicAttributes attrset;
try {
attrset = (BasicAttributes)super.clone();
} catch (CloneNotSupportedException e) {
attrset = new BasicAttributes(ignoreCase);
}
attrset.attrs = (Hashtable)attrs.clone();
return attrset;
}
public boolean isCaseIgnored() {
return ignoreCase;
}
public int size() {
return attrs.size();
}
public Attribute get(String attrID) {
Attribute attr = (Attribute) attrs.get(
ignoreCase ? attrID.toLowerCase() : attrID);
return (attr);
}
public NamingEnumeration<Attribute> getAll() {
return new AttrEnumImpl();
}
public NamingEnumeration<String> getIDs() {
return new IDEnumImpl();
}
public Attribute put(String attrID, Object val) {
return this.put(new BasicAttribute(attrID, val));
}
public Attribute put(Attribute attr) {
String id = attr.getID();
if (ignoreCase) {
id = id.toLowerCase();
}
return (Attribute)attrs.put(id, attr);
}
public Attribute remove(String attrID) {
String id = (ignoreCase ? attrID.toLowerCase() : attrID);
return (Attribute)attrs.remove(id);
}
/**
* Generates the string representation of this attribute set.
* The string consists of each attribute identifier and the contents
* of each attribute. The contents of this string is useful
* for debugging and is not meant to be interpreted programmatically.
*
* @return A non-null string listing the contents of this attribute set.
*/
public String toString() {
if (attrs.size() == 0) {
return("No attributes");
} else {
return attrs.toString();
}
}
/**
* Determines whether this <tt>BasicAttributes</tt> is equal to another
* <tt>Attributes</tt>
* Two <tt>Attributes</tt> are equal if they are both instances of
* <tt>Attributes</tt>,
* treat the case of attribute IDs the same way, and contain the
* same attributes. Each <tt>Attribute</tt> in this <tt>BasicAttributes</tt>
* is checked for equality using <tt>Object.equals()</tt>, which may have
* be overridden by implementations of <tt>Attribute</tt>).
* If a subclass overrides <tt>equals()</tt>,
* it should override <tt>hashCode()</tt>
* as well so that two <tt>Attributes</tt> instances that are equal
* have the same hash code.
* @param obj the possibly null object to compare against.
*
* @return true If obj is equal to this BasicAttributes.
* @see #hashCode
*/
public boolean equals(Object obj) {
if ((obj != null) && (obj instanceof Attributes)) {
Attributes target = (Attributes)obj;
// Check case first
if (ignoreCase != target.isCaseIgnored()) {
return false;
}
if (size() == target.size()) {
Attribute their, mine;
try {
NamingEnumeration theirs = target.getAll();
while (theirs.hasMore()) {
their = (Attribute)theirs.next();
mine = get(their.getID());
if (!their.equals(mine)) {
return false;
}
}
} catch (NamingException e) {
return false;
}
return true;
}
}
return false;
}
/**
* Calculates the hash code of this BasicAttributes.
*<p>
* The hash code is computed by adding the hash code of
* the attributes of this object. If this BasicAttributes
* ignores case of its attribute IDs, one is added to the hash code.
* If a subclass overrides <tt>hashCode()</tt>,
* it should override <tt>equals()</tt>
* as well so that two <tt>Attributes</tt> instances that are equal
* have the same hash code.
*
* @return an int representing the hash code of this BasicAttributes instance.
* @see #equals
*/
public int hashCode() {
int hash = (ignoreCase ? 1 : 0);
try {
NamingEnumeration all = getAll();
while (all.hasMore()) {
hash += all.next().hashCode();
}
} catch (NamingException e) {}
return hash;
}
/**
* Overridden to avoid exposing implementation details.
* @serialData Default field (ignoreCase flag -- a boolean), followed by
* the number of attributes in the set
* (an int), and then the individual Attribute objects.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject(); // write out the ignoreCase flag
s.writeInt(attrs.size());
Enumeration attrEnum = attrs.elements();
while (attrEnum.hasMoreElements()) {
s.writeObject(attrEnum.nextElement());
}
}
/**
* Overridden to avoid exposing implementation details.
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject(); // read in the ignoreCase flag
int n = s.readInt(); // number of attributes
attrs = (n >= 1)
? new Hashtable(n * 2)
: new Hashtable(2); // can't have initial size of 0 (grrr...)
while (--n >= 0) {
put((Attribute)s.readObject());
}
}
class AttrEnumImpl implements NamingEnumeration<Attribute> {
Enumeration<Attribute> elements;
public AttrEnumImpl() {
this.elements = attrs.elements();
}
public boolean hasMoreElements() {
return elements.hasMoreElements();
}
public Attribute nextElement() {
return elements.nextElement();
}
public boolean hasMore() throws NamingException {
return hasMoreElements();
}
public Attribute next() throws NamingException {
return nextElement();
}
public void close() throws NamingException {
elements = null;
}
}
class IDEnumImpl implements NamingEnumeration<String> {
Enumeration<Attribute> elements;
public IDEnumImpl() {
// Walking through the elements, rather than the keys, gives
// us attribute IDs that have not been converted to lowercase.
this.elements = attrs.elements();
}
public boolean hasMoreElements() {
return elements.hasMoreElements();
}
public String nextElement() {
Attribute attr = elements.nextElement();
return attr.getID();
}
public boolean hasMore() throws NamingException {
return hasMoreElements();
}
public String next() throws NamingException {
return nextElement();
}
public void close() throws NamingException {
elements = null;
}
}
/**
* Use serialVersionUID from JNDI 1.1.1 for interoperability.
*/
private static final long serialVersionUID = 4980164073184639448L;
}