001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: Attr.java,v 1.4 2009/01/28 05:34:49 ww203982 Exp $
026 *
027 */
028
029/**
030 * Portions Copyrighted [2011] [ForgeRock AS]
031 */
032package com.iplanet.services.ldap;
033
034import java.util.ArrayList;
035import java.util.Locale;
036
037import com.sun.identity.shared.ldap.LDAPAttribute;
038
039/**
040 * Represents an attribute value pair in UMS. The value of an attribute can be
041 * of multiple values.
042 * @supported.api
043 */
044public class Attr implements java.io.Serializable, java.lang.Cloneable {
045
046    String _name;
047
048    private ArrayList _stringValues;
049
050    private ArrayList _byteValues;
051
052    private LDAPAttribute _ldapAttribute;
053
054    /**
055     * Default constructor
056     * @supported.api
057     */
058    public Attr() {
059    }
060
061    /**
062     * Constructs an attribute value pair with no value.
063     * 
064     * @param name
065     *            attribute name
066     * @supported.api
067     */
068    public Attr(String name) {
069        _name = name.toLowerCase();
070    }
071
072    /**
073     * Construct an attribute value pair with a single string value.
074     * 
075     * @param name
076     *            the name of attribute
077     * @param value
078     *            string value of attribute
079     * @supported.api
080     */
081    public Attr(String name, String value) {
082        _name = name.toLowerCase();
083        _stringValues = new ArrayList(1);
084        _stringValues.add(value);
085    }
086
087    /**
088     * Construct an attribute value pair with a multiple string values.
089     * 
090     * @param name
091     *            the name of attribute
092     * @param value
093     *            multiple string values of attribute
094     * @supported.api
095     */
096    public Attr(String name, String[] value) {
097        _name = name.toLowerCase();
098        int size = value.length;
099        _stringValues = new ArrayList(size);
100        for (int i = 0; i < size; i++) {
101            _stringValues.add(value[i]);
102        }
103    }
104
105    /**
106     * Constructs an attribute value pair with byte array.
107     * 
108     * @param name
109     *            attribute name
110     * @param value
111     *            byte array as input for value
112     * @supported.api
113     */
114    public Attr(String name, byte[] value) {
115        _name = name.toLowerCase();
116        _byteValues = new ArrayList(1);
117        _byteValues.add(value);
118    }
119
120    /**
121     * Constructs an attribute value pair with array of byte array.
122     * 
123     * @param name
124     *            attribute name
125     * @param value
126     *            array of byte array as input for value
127     * @supported.api
128     */
129    public Attr(String name, byte[][] value) {
130        _name = name.toLowerCase();
131        _byteValues = new ArrayList(1);
132        int size = value.length;
133        for (int i = 0; i < size; i++) {
134            _byteValues.add(value[i]);
135        }
136    }
137
138    /**
139     * Construct an attribute based on a LDAP attribute
140     * 
141     * @param attr
142     *            ldap attribute to construct from
143     */
144    public Attr(LDAPAttribute attr) {
145        _name = attr.getName().toLowerCase();
146        _ldapAttribute = attr; // attr.clone() ?
147    }
148
149    /**
150     * Map to a ldap attribute
151     * 
152     * @return an ldap attribute
153     */
154    public LDAPAttribute toLDAPAttribute() {
155        int size = 0;
156        LDAPAttribute ldapAttribute = null;
157        if (_stringValues != null) {
158            size = _stringValues.size();
159            if (size == 0) {
160                ldapAttribute = new LDAPAttribute(_name);
161            } else if (size == 1) {
162                ldapAttribute = new LDAPAttribute(_name, (String) _stringValues
163                        .get(0));
164            } else if (size > 1) {
165                ldapAttribute = new LDAPAttribute(_name);
166                for (int i = 0; i < size; i++) {
167                    ldapAttribute.addValue((String) _stringValues.get(i));
168                }
169            }
170        } else if (_byteValues != null) {
171            ldapAttribute = new LDAPAttribute(_name);
172            size = _byteValues.size();
173            for (int i = 0; i < size; i++) {
174                ldapAttribute.addValue((byte[]) _byteValues.get(i)); // clone?
175            }
176        } else if (_ldapAttribute != null) {
177            ldapAttribute = _ldapAttribute; // clone?
178        } else if (_name != null) {
179            ldapAttribute = new LDAPAttribute(_name);
180        }
181        return ldapAttribute;
182    }
183
184    /**
185     * Set value of an attribute
186     * 
187     * @param value
188     *            the attribute value to be set
189     * @supported.api
190     */
191    public void setValue(String value) {
192        if (_stringValues == null) {
193            setupStringValues();
194        }
195        _stringValues.clear();
196        addValue(value);
197    }
198
199    /**
200     * Add a string value to the attribute
201     * 
202     * @param value
203     *            value to be added to the attribute
204     * @supported.api
205     */
206    public void addValue(String value) {
207        if (_stringValues == null) {
208            setupStringValues();
209        }
210        if (!_stringValues.contains(value)) {
211            _stringValues.add(value);
212        }
213    }
214
215    /**
216     * Add mulitple string values to the attribute
217     * 
218     * @param values
219     *            string values to be added to the attribute
220     * @supported.api
221     */
222    public void addValues(String[] values) {
223        int size = values.length;
224        for (int i = 0; i < size; i++) {
225            addValue(values[i]);
226        }
227    }
228
229    /**
230     * Remove a specified string value in the attribute
231     * 
232     * @param value
233     *            specified value to be remvoed from the value array
234     * @supported.api
235     */
236    public void removeValue(String value) {
237        if (_stringValues == null) {
238            setupStringValues();
239        }
240        int size = _stringValues.size();
241        for (int i = 0; i < size; i++) {
242            if (_stringValues.get(i).equals(value)) {
243                _stringValues.remove(i);
244                break;
245            }
246        }
247    }
248
249    /**
250     * Set value of an attribute
251     * 
252     * @param value
253     *            the attribute value to be set
254     * @supported.api
255     */
256    public void setValue(byte[] value) {
257        if (_byteValues == null) {
258            setupByteValues();
259        }
260        _byteValues.clear();
261        addValue(value);
262    }
263
264    /**
265     * Add a byte array value to the attribute
266     * 
267     * @param value
268     *            byte array value to be added to the attribute
269     * @supported.api
270     */
271    public void addValue(byte[] value) {
272        if (_byteValues == null) {
273            setupByteValues();
274        }
275        _byteValues.add(value); // clone?
276    }
277
278    /**
279     * Add a list byte array values to the attribute
280     * 
281     * @param values
282     *            of byte array values to be added to the attribute
283     * @supported.api
284     */
285    public void addValues(byte[][] values) {
286        int size = values.length;
287        for (int i = 0; i < size; i++) {
288            addValue(values[i]);
289        }
290    }
291
292    /**
293     * Remove a specified string value in the attribute
294     * 
295     * @param value
296     *            specified value to be remvoed from the value array
297     * @supported.api
298     */
299    public void removeValue(byte[] value) {
300        if (_byteValues == null) {
301            setupByteValues();
302        }
303        int size = _byteValues.size();
304        for (int i = 0; i < size; i++) {
305            // we might have to change the logic here to compare each byte
306            if (_byteValues.get(i).equals(value)) {
307                _byteValues.remove(i);
308                break;
309            }
310        }
311    }
312
313    /**
314     * Get name of an UMS attribute
315     * 
316     * @return name of an UMS attribute
317     * @supported.api
318     */
319    public String getName() {
320        return _name;
321    }
322
323    /**
324     * Get name of attribute in a given Locale
325     * 
326     * @param locale
327     *            Given locale for the attribute name to return
328     * @return name of an UMS attribute
329     * @supported.api
330     */
331    public String getName(Locale locale) {
332        return Attr.getName(_name, locale);
333    }
334
335    /**
336     * Get attribute name with locale input.
337     * 
338     * @param attrName
339     *            name of the attribute
340     * @param locale
341     *            desired locale for the attribute
342     * @return attribute name with locale attached for retrieval
343     * @supported.api
344     */
345    static public String getName(String attrName, Locale locale) {
346        String name = null;
347        String baseName = getBaseName(attrName);
348        if (locale == null) {
349            name = baseName;
350        } else {
351
352            // TODO: ??? check if locale.toString method provides the
353            // contents in locale.getLanguage, locale.getSubtype, and
354            // locale.getVariant methods that match the language subtypes
355            // in LDAP.
356            //
357            String localeStr = locale.toString();
358            if (localeStr.length() > 0) {
359                StringBuilder sb = new StringBuilder(baseName);
360                sb.append(";lang-");
361                sb.append(localeStr);
362                name = sb.toString();
363            }
364        }
365        return name;
366    }
367
368    /**
369     * Get base name for the attribute. e.g, the base name
370     * of "cn;lang-en" or "cn;lang-ja" is "cn"
371     * 
372     * @return basename of an attribute
373     * @supported.api
374     */
375    public String getBaseName() {
376        String baseName = null;
377        if (_name == null) {
378            baseName = null;
379        } else {
380            baseName = LDAPAttribute.getBaseName(_name);
381        }
382        return baseName;
383    }
384
385    /**
386     * Get base name for an attribute name. e.g, the base
387     * name of "cn;lang-en" or "cn;lang-ja" is "cn"
388     * 
389     * @return basename of the given attribute name
390     * @supported.api
391     */
392    static public String getBaseName(String attrName) {
393        return LDAPAttribute.getBaseName(attrName);
394    }
395
396    /**
397     * Get one string value of the attribute
398     * 
399     * @return one value of the attribute
400     * @supported.api
401     */
402    public String getValue() {
403        String value = null;
404        if (_stringValues == null) {
405            setupStringValues();
406        }
407        if (!_stringValues.isEmpty()) {
408            value = (String) _stringValues.get(0);
409        }
410        return value;
411    }
412
413    /**
414     * Get the string values of the attribute
415     * 
416     * @return the values in an string array
417     * @supported.api
418     */
419    public String[] getStringValues() {
420        // Returning a colletion would be better, but would break existing
421        // higher level
422        // code
423
424        // com.iplanet.ums.Pauser.pause("10", "_stringValues : " +
425        // _stringValues);
426        // com.iplanet.ums.Pauser.pause("10", "_stringValue : " + _stringValue);
427        // System.out.println("_stringValue : " + _stringValue);
428        // System.out.println("_stringValues : " + _stringValues);
429        String[] stringValues = null;
430        if (_stringValues == null) {
431            setupStringValues();
432        }
433        int size = _stringValues.size();
434        stringValues = new String[size];
435        for (int i = 0; i < size; i++) {
436            stringValues[i] = (String) _stringValues.get(i);
437        }
438        return stringValues;
439    }
440
441    /**
442     * Checks whether the given value already exist for
443     * the attribute
444     * 
445     * @param value
446     *            the value to check for
447     * @return <code>true</code> if the value already exists,
448     *         <code>false</code> otherwise
449     * @supported.api
450     */
451    public boolean contains(String value) {
452        boolean contained = false;
453        if (_stringValues == null) {
454            setupStringValues();
455        }
456        int size = _stringValues.size();
457        for (int i = 0; i < size; i++) {
458            if (_stringValues.get(i).equals(value)) {
459                contained = true;
460                break;
461            }
462        }
463        return contained;
464    }
465
466    /**
467     * Get one byte[] value of the attribute Returning a
468     * colletion would be better, but will not be consistent with the method
469     * getStringValues()
470     * 
471     * @return one byte[] value
472     * @supported.api
473     */
474    public byte[] getByteValue() {
475        // Not cloning the value before returning. Do we need to clone?
476        byte[] value = null;
477        if (_byteValues == null) {
478            setupByteValues();
479        }
480        if (!_byteValues.isEmpty()) {
481            value = (byte[]) _byteValues.get(0);
482        }
483        return value;
484    }
485
486    /**
487     * Get the byte[] values of the attribute
488     * 
489     * @return the byte[] values in array
490     * @supported.api
491     */
492    public byte[][] getByteValues() {
493        // Not cloning the values before returning. Do we need to clone?
494        byte[][] byteValues = null;
495        if (_byteValues == null) {
496            setupByteValues();
497        }
498        int size = _byteValues.size();
499        byteValues = new byte[size][];
500        for (int i = 0; i < size; i++) {
501            byteValues[i] = (byte[]) _byteValues.get(i);
502        }
503        return byteValues;
504    }
505
506    /**
507     * Checks whether the given value already exist for
508     * the attribute
509     * 
510     * @param value
511     *            the value to check for
512     * @return <code>true</code> if the value already exists,
513     *         <code>false</code> otherwise
514     * @supported.api
515     */
516    public boolean contains(byte[] value) {
517        boolean contained = false;
518        if (_byteValues == null) {
519            setupByteValues();
520        }
521        int size = _byteValues.size();
522        for (int i = 0; i < size; i++) {
523            // we might have to change the logic here to compare each byte
524            if (_byteValues.get(i).equals(value)) {
525                contained = true;
526                break;
527            }
528        }
529        return contained;
530    }
531
532    /**
533     * Get the number of values of the attribute
534     * 
535     * @return The number of values of the attribute
536     * @supported.api
537     */
538    public int size() {
539        int size = 0;
540        if (_stringValues != null) {
541            size = _stringValues.size();
542        } else if (_byteValues != null) {
543            size = _byteValues.size();
544        } else if (_ldapAttribute != null) {
545            size = _ldapAttribute.size();
546        }
547        return size;
548    }
549
550    /**
551     * Return a copy of the object
552     * 
553     * @return A copy of the object
554     * @supported.api
555     */
556    public Object clone() {
557        /*
558         * TO DO : revisit and do proper deep cloning?
559         */
560        Attr theClone = null;
561        try {
562            theClone = (Attr) super.clone();
563        } catch (Exception e) {
564        }
565        if (_stringValues != null) {
566            theClone._stringValues = (ArrayList) _stringValues.clone();
567        }
568        if (_byteValues != null) {
569            theClone._byteValues = (ArrayList) _byteValues.clone();
570        } else if (_ldapAttribute != null) {
571            theClone._ldapAttribute = _ldapAttribute; // clone?
572        }
573        return theClone;
574    }
575
576    /**
577     * Retrieves the string representation of an attribute
578     * 
579     * @return string representation of the attribute.
580     * @supported.api
581     */
582    public String toString() {
583        if (_stringValues == null) {
584            setupStringValues();
585        }
586        return "Name : " + _name + _stringValues;
587    }
588
589    /**
590     */
591    private void setupStringValues() {
592        if (_ldapAttribute != null) {
593            String[] values = _ldapAttribute.getStringValueArray();
594            int size = values.length;
595            _stringValues = new ArrayList(size);
596            for (int i = 0; i < size; i++) {
597                _stringValues.add(values[i]);
598            }
599        } else {
600            _stringValues = new ArrayList();
601        }
602    }
603
604    /**
605     */
606    private void setupByteValues() {
607        if (_ldapAttribute != null) {
608            byte[][] values = _ldapAttribute.getByteValueArray();
609            int size = values.length;
610            _byteValues = new ArrayList(size);
611            for (int i = 0; i < size; i++) {
612                _byteValues.add(values[i]);
613            }
614        } else {
615            _byteValues = new ArrayList();
616        }
617    }
618
619}