001/* BasicAttribute.java --
002   Copyright (C) 2000, 2001, 2004, 2006  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.naming.directory;
040
041import java.io.IOException;
042import java.io.ObjectInputStream;
043import java.io.ObjectOutputStream;
044import java.util.NoSuchElementException;
045import java.util.Vector;
046
047import javax.naming.NamingEnumeration;
048import javax.naming.NamingException;
049import javax.naming.OperationNotSupportedException;
050
051/**
052 * @author Tom Tromey (tromey@redhat.com)
053 * @date June 20, 2001
054 * @since 1.3
055 */
056public class BasicAttribute implements Attribute
057{
058  private static final long serialVersionUID = 6743528196119291326L;
059
060  /** The ID of this attribute.  */
061  protected String attrID;
062  /** True if this attribute's values are ordered.  */
063  protected boolean ordered;
064  /** Values for this attribute.  */
065  protected transient Vector<Object> values;
066
067  // Used by cloning.
068  private BasicAttribute ()
069  {
070  }
071
072  public BasicAttribute (String id)
073  {
074    this (id, false);
075  }
076
077  public BasicAttribute (String id, boolean ordered)
078  {
079    attrID = id;
080    this.ordered = ordered;
081    values = new Vector<Object> ();
082  }
083
084  public BasicAttribute (String id, Object value)
085  {
086    this (id, value, false);
087  }
088
089  public BasicAttribute (String id, Object value, boolean ordered)
090  {
091    attrID = id;
092    this.ordered = ordered;
093    values = new Vector<Object> ();
094    values.add (value);
095  }
096
097  public void add (int index, Object val)
098  {
099    if (! ordered && contains (val))
100      throw new IllegalStateException ("value already in attribute");
101    values.add (index, val);
102  }
103
104  public boolean add (Object val)
105  {
106    if (! ordered && contains (val))
107      throw new IllegalStateException ("value already in attribute");
108    return values.add (val);
109  }
110
111  public void clear ()
112  {
113    values.clear ();
114  }
115
116  public Object clone ()
117  {
118    BasicAttribute c = new BasicAttribute ();
119    c.attrID = attrID;
120    c.ordered = ordered;
121    c.values = (Vector<Object>) values.clone ();
122    return c;
123  }
124
125  public boolean contains (Object val)
126  {
127    for (int i = 0; i < values.size (); ++i)
128      {
129        if (equals (val, values.get (i)))
130          return true;
131      }
132
133    return false;
134  }
135
136  public boolean equals (Object obj)
137  {
138    if (! (obj instanceof BasicAttribute))
139      return false;
140    BasicAttribute b = (BasicAttribute) obj;
141
142    if (ordered != b.ordered
143        || ! attrID.equals (b.attrID)
144        || values.size () != b.values.size ())
145      return false;
146
147    for (int i = 0; i < values.size (); ++i)
148      {
149        boolean ok = false;
150        if (ordered)
151          ok = equals (values.get (i), b.values.get (i));
152        else
153          {
154            for (int j = 0; j < b.values.size (); ++j)
155              {
156                if (equals (values.get (i), b.values.get (j)))
157                  {
158                    ok = true;
159                    break;
160                  }
161              }
162          }
163
164        if (! ok)
165          return false;
166      }
167
168    return true;
169  }
170
171  public Object get ()
172    throws NamingException
173  {
174    if (values.size () == 0)
175      throw new NoSuchElementException ("no values");
176    return get (0);
177  }
178
179  public Object get (int index)
180    throws NamingException
181  {
182    return values.get (index);
183  }
184
185  public NamingEnumeration<?> getAll ()
186    throws NamingException
187  {
188    return new BasicAttributeEnumeration ();
189  }
190
191  public DirContext getAttributeDefinition ()
192    throws OperationNotSupportedException, NamingException
193  {
194    throw new OperationNotSupportedException ();
195  }
196
197  public DirContext getAttributeSyntaxDefinition ()
198    throws OperationNotSupportedException, NamingException
199  {
200    throw new OperationNotSupportedException ();
201  }
202
203  public String getID ()
204  {
205    return attrID;
206  }
207
208  public int hashCode ()
209  {
210    int val = attrID.hashCode ();
211    for (int i = 0; i < values.size (); ++i)
212      {
213        Object o = values.get (i);
214        if (o == null)
215          {
216            // Nothing.
217          }
218        else if (o instanceof Object[])
219          {
220            Object[] a = (Object[]) o;
221            for (int j = 0; j < a.length; ++j)
222              val += a[j].hashCode ();
223          }
224        else
225          val += o.hashCode ();
226      }
227
228    return val;
229  }
230
231  public boolean isOrdered ()
232  {
233    return ordered;
234  }
235
236  public Object remove (int index)
237  {
238    return values.remove (index);
239  }
240
241  public boolean remove (Object val)
242  {
243    for (int i = 0; i < values.size (); ++i)
244      {
245        if (equals (val, values.get (i)))
246          {
247            values.remove (i);
248            return true;
249          }
250      }
251
252    return false;
253  }
254
255  public Object set (int index, Object val)
256  {
257    if (! ordered && contains (val))
258      throw new IllegalStateException ("value already in attribute");
259    return values.set (index, val);
260  }
261
262  public int size ()
263  {
264    return values.size ();
265  }
266
267  public String toString ()
268  {
269    String r = attrID;
270    for (int i = 0; i < values.size (); ++i)
271      r += ";" + values.get (i).toString ();
272    return r;
273  }
274
275  // This is used for testing equality of two Objects according to our
276  // local rules.
277  private boolean equals (Object one, Object two)
278  {
279    if (one == null)
280      return two == null;
281
282    if (one instanceof Object[])
283      {
284        if (! (two instanceof Object[]))
285          return false;
286
287        Object[] aone = (Object[]) one;
288        Object[] atwo = (Object[]) two;
289
290        if (aone.length != atwo.length)
291          return false;
292
293        for (int i = 0; i < aone.length; ++i)
294          {
295            if (! aone[i].equals (atwo[i]))
296              return false;
297          }
298
299        return true;
300      }
301
302    return one.equals (two);
303  }
304
305  private void readObject(ObjectInputStream s)
306    throws IOException, ClassNotFoundException
307  {
308    s.defaultReadObject();
309    int size = s.readInt();
310    values = new Vector<Object>(size);
311    for (int i=0; i < size; i++)
312      values.add(s.readObject());
313  }
314
315  private void writeObject(ObjectOutputStream s) throws IOException
316  {
317    s.defaultWriteObject();
318    s.writeInt(values.size());
319    for (int i=0; i < values.size(); i++)
320      s.writeObject(values.get(i));
321  }
322
323  // Used when enumerating this attribute.
324  private class BasicAttributeEnumeration implements NamingEnumeration
325  {
326    int where = 0;
327
328    public BasicAttributeEnumeration ()
329    {
330    }
331
332    public void close () throws NamingException
333    {
334    }
335
336    public boolean hasMore () throws NamingException
337    {
338      return hasMoreElements ();
339    }
340
341    public Object next () throws NamingException
342    {
343      return nextElement ();
344    }
345
346    public boolean hasMoreElements ()
347    {
348      return where < values.size ();
349    }
350
351    public Object nextElement () throws NoSuchElementException
352    {
353      if (where == values.size ())
354        throw new NoSuchElementException ("no more elements");
355      return values.get (where++);
356    }
357  }
358}