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 * Portions Copyrighted 2011-2015 ForgeRock AS.
028 */
029
030package com.iplanet.services.ldap;
031
032import java.util.ArrayList;
033import java.util.List;
034import java.util.Locale;
035import java.util.StringTokenizer;
036
037import org.forgerock.opendj.ldap.Attribute;
038import org.forgerock.opendj.ldap.Attributes;
039
040/**
041 * Represents an attribute value pair in UMS. The value of an attribute can be
042 * of multiple values.
043 * @supported.api
044 */
045public class Attr implements java.io.Serializable, java.lang.Cloneable {
046
047    String _name;
048
049    private List<String> _stringValues;
050
051    private List<byte[]> _byteValues;
052
053    private Attribute _ldapAttribute;
054
055    /**
056     * Default constructor
057     * @supported.api
058     */
059    public Attr() {
060    }
061
062    /**
063     * Constructs an attribute value pair with no value.
064     * 
065     * @param name
066     *            attribute name
067     * @supported.api
068     */
069    public Attr(String name) {
070        _name = name.toLowerCase();
071    }
072
073    /**
074     * Construct an attribute value pair with a single string value.
075     * 
076     * @param name
077     *            the name of attribute
078     * @param value
079     *            string value of attribute
080     * @supported.api
081     */
082    public Attr(String name, String value) {
083        _name = name.toLowerCase();
084        _stringValues = new ArrayList<>(1);
085        _stringValues.add(value);
086    }
087
088    /**
089     * Construct an attribute value pair with a multiple string values.
090     * 
091     * @param name
092     *            the name of attribute
093     * @param value
094     *            multiple string values of attribute
095     * @supported.api
096     */
097    public Attr(String name, String[] value) {
098        _name = name.toLowerCase();
099        int size = value.length;
100        _stringValues = new ArrayList<>(size);
101        for (int i = 0; i < size; i++) {
102            _stringValues.add(value[i]);
103        }
104    }
105
106    /**
107     * Constructs an attribute value pair with byte array.
108     * 
109     * @param name
110     *            attribute name
111     * @param value
112     *            byte array as input for value
113     * @supported.api
114     */
115    public Attr(String name, byte[] value) {
116        _name = name.toLowerCase();
117        _byteValues = new ArrayList<>(1);
118        _byteValues.add(value);
119    }
120
121    /**
122     * Constructs an attribute value pair with array of byte array.
123     * 
124     * @param name
125     *            attribute name
126     * @param value
127     *            array of byte array as input for value
128     * @supported.api
129     */
130    public Attr(String name, byte[][] value) {
131        _name = name.toLowerCase();
132        _byteValues = new ArrayList<>(1);
133        int size = value.length;
134        for (int i = 0; i < size; i++) {
135            _byteValues.add(value[i]);
136        }
137    }
138
139    /**
140     * Construct an attribute based on a LDAP attribute
141     * 
142     * @param attr
143     *            ldap attribute to construct from
144     */
145    public Attr(Attribute attr) {
146        _name = attr.getAttributeDescriptionAsString().toLowerCase();
147        _ldapAttribute = attr; // attr.clone() ?
148    }
149
150    /**
151     * Map to a ldap attribute
152     * 
153     * @return an ldap attribute
154     */
155    public Attribute toLDAPAttribute() {
156        Attribute ldapAttribute = null;
157        if (_stringValues != null) {
158            int size = _stringValues.size();
159            if (size == 0) {
160                ldapAttribute = Attributes.emptyAttribute(_name);
161            } else if (size == 1) {
162                ldapAttribute = Attributes.singletonAttribute(_name, _stringValues.get(0));
163            } else if (size > 1) {
164                ldapAttribute = Attributes.emptyAttribute(_name);
165                for (String value : _stringValues) {
166                    ldapAttribute.add(value);
167                }
168            }
169        } else if (_byteValues != null) {
170            ldapAttribute = Attributes.emptyAttribute(_name);
171            for (byte[] value : _byteValues) {
172                ldapAttribute.add(value); // clone?
173            }
174        } else if (_ldapAttribute != null) {
175            ldapAttribute = _ldapAttribute; // clone?
176        } else if (_name != null) {
177            ldapAttribute = Attributes.emptyAttribute(_name);
178        }
179        return ldapAttribute;
180    }
181
182    /**
183     * Set value of an attribute
184     * 
185     * @param value
186     *            the attribute value to be set
187     * @supported.api
188     */
189    public void setValue(String value) {
190        if (_stringValues == null) {
191            setupStringValues();
192        }
193        _stringValues.clear();
194        addValue(value);
195    }
196
197    /**
198     * Add a string value to the attribute
199     * 
200     * @param value
201     *            value to be added to the attribute
202     * @supported.api
203     */
204    public void addValue(String value) {
205        if (_stringValues == null) {
206            setupStringValues();
207        }
208        if (!_stringValues.contains(value)) {
209            _stringValues.add(value);
210        }
211    }
212
213    /**
214     * Add mulitple string values to the attribute
215     * 
216     * @param values
217     *            string values to be added to the attribute
218     * @supported.api
219     */
220    public void addValues(String[] values) {
221        int size = values.length;
222        for (int i = 0; i < size; i++) {
223            addValue(values[i]);
224        }
225    }
226
227    /**
228     * Remove a specified string value in the attribute
229     * 
230     * @param value
231     *            specified value to be remvoed from the value array
232     * @supported.api
233     */
234    public void removeValue(String value) {
235        if (_stringValues == null) {
236            setupStringValues();
237        }
238        int size = _stringValues.size();
239        for (int i = 0; i < size; i++) {
240            if (_stringValues.get(i).equals(value)) {
241                _stringValues.remove(i);
242                break;
243            }
244        }
245    }
246
247    /**
248     * Set value of an attribute
249     * 
250     * @param value
251     *            the attribute value to be set
252     * @supported.api
253     */
254    public void setValue(byte[] value) {
255        if (_byteValues == null) {
256            setupByteValues();
257        }
258        _byteValues.clear();
259        addValue(value);
260    }
261
262    /**
263     * Add a byte array value to the attribute
264     * 
265     * @param value
266     *            byte array value to be added to the attribute
267     * @supported.api
268     */
269    public void addValue(byte[] value) {
270        if (_byteValues == null) {
271            setupByteValues();
272        }
273        _byteValues.add(value); // clone?
274    }
275
276    /**
277     * Add a list byte array values to the attribute
278     * 
279     * @param values
280     *            of byte array values to be added to the attribute
281     * @supported.api
282     */
283    public void addValues(byte[][] values) {
284        int size = values.length;
285        for (int i = 0; i < size; i++) {
286            addValue(values[i]);
287        }
288    }
289
290    /**
291     * Remove a specified string value in the attribute
292     * 
293     * @param value
294     *            specified value to be remvoed from the value array
295     * @supported.api
296     */
297    public void removeValue(byte[] value) {
298        if (_byteValues == null) {
299            setupByteValues();
300        }
301        int size = _byteValues.size();
302        for (int i = 0; i < size; i++) {
303            // we might have to change the logic here to compare each byte
304            if (_byteValues.get(i).equals(value)) {
305                _byteValues.remove(i);
306                break;
307            }
308        }
309    }
310
311    /**
312     * Get name of an UMS attribute
313     * 
314     * @return name of an UMS attribute
315     * @supported.api
316     */
317    public String getName() {
318        return _name;
319    }
320
321    /**
322     * Get name of attribute in a given Locale
323     * 
324     * @param locale
325     *            Given locale for the attribute name to return
326     * @return name of an UMS attribute
327     * @supported.api
328     */
329    public String getName(Locale locale) {
330        return Attr.getName(_name, locale);
331    }
332
333    /**
334     * Get attribute name with locale input.
335     * 
336     * @param attrName
337     *            name of the attribute
338     * @param locale
339     *            desired locale for the attribute
340     * @return attribute name with locale attached for retrieval
341     * @supported.api
342     */
343    static public String getName(String attrName, Locale locale) {
344        String name = null;
345        String baseName = getBaseName(attrName);
346        if (locale == null) {
347            name = baseName;
348        } else {
349
350            // TODO: ??? check if locale.toString method provides the
351            // contents in locale.getLanguage, locale.getSubtype, and
352            // locale.getVariant methods that match the language subtypes
353            // in LDAP.
354            //
355            String localeStr = locale.toString();
356            if (localeStr.length() > 0) {
357                StringBuilder sb = new StringBuilder(baseName);
358                sb.append(";lang-");
359                sb.append(localeStr);
360                name = sb.toString();
361            }
362        }
363        return name;
364    }
365
366    /**
367     * Get base name for the attribute. e.g, the base name
368     * of "cn;lang-en" or "cn;lang-ja" is "cn"
369     * 
370     * @return basename of an attribute
371     * @supported.api
372     */
373    public String getBaseName() {
374        if (_name != null) {
375            return getBaseName(getName());
376        }
377        return null;
378    }
379
380    /**
381     * Get base name for an attribute name. e.g, the base
382     * name of "cn;lang-en" or "cn;lang-ja" is "cn"
383     * 
384     * @return basename of the given attribute name
385     * @supported.api
386     */
387    static public String getBaseName(String attrName) {
388        String basename = attrName;
389        StringTokenizer st = new StringTokenizer(attrName, ";");
390        if( st.hasMoreElements() )
391            // First element is base name
392            basename = (String)st.nextElement();
393        return basename;
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 = new ArrayList<>(_stringValues);
567        }
568        if (_byteValues != null) {
569            theClone._byteValues = new ArrayList<>(_byteValues);
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.toArray(new String[0]);
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.toArray(new byte[0][]);
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}