001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.protocols.ldap;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    import java.util.Iterator;
034    import java.util.LinkedHashSet;
035    import java.util.List;
036    
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.types.Attribute;
040    import org.opends.server.types.AttributeType;
041    import org.opends.server.types.AttributeValue;
042    import org.opends.server.types.LDAPException;
043    import org.opends.server.types.RawAttribute;
044    
045    import static org.opends.server.loggers.debug.DebugLogger.*;
046    import org.opends.server.loggers.debug.DebugTracer;
047    import static org.opends.messages.ProtocolMessages.*;
048    import static org.opends.server.protocols.ldap.LDAPResultCode.*;
049    import static org.opends.server.util.ServerConstants.*;
050    import static org.opends.server.util.StaticUtils.*;
051    
052    
053    
054    
055    /**
056     * This class defines the data structures and methods to use when interacting
057     * with an LDAP attribute, which is the basic unit of information in an LDAP
058     * entry.
059     */
060    public class LDAPAttribute
061           extends RawAttribute
062    {
063      /**
064       * The tracer object for the debug logger.
065       */
066      private static final DebugTracer TRACER = getTracer();
067    
068      // The set of values for this attribute.
069      private ArrayList<ASN1OctetString> values;
070    
071      // The attribute type for this attribute.
072      private String attributeType;
073    
074    
075    
076      /**
077       * Creates a new LDAP attribute with the provided type and no values.
078       *
079       * @param  attributeType  The attribute type for this attribute.
080       */
081      public LDAPAttribute(String attributeType)
082      {
083        this.attributeType = attributeType;
084    
085        values = new ArrayList<ASN1OctetString>(0);
086      }
087    
088    
089    
090      /**
091       * Creates a new LDAP attribute with the provided type and no values.
092       *
093       * @param  attributeType  The attribute type for this attribute.
094       * @param  value          The value to use for this attribute.
095       */
096      public LDAPAttribute(String attributeType, String value)
097      {
098        this.attributeType = attributeType;
099    
100        values = new ArrayList<ASN1OctetString>(1);
101        values.add(new ASN1OctetString(value));
102      }
103    
104    
105    
106      /**
107       * Creates a new LDAP attribute with the provided type and no values.
108       *
109       * @param  attributeType  The attribute type for this attribute.
110       * @param  value          The value to use for this attribute.
111       */
112      public LDAPAttribute(String attributeType, ASN1OctetString value)
113      {
114        this.attributeType = attributeType;
115    
116        values = new ArrayList<ASN1OctetString>(1);
117        values.add(value);
118      }
119    
120    
121    
122      /**
123       * Creates a new LDAP attribute with the provided type and values.
124       *
125       * @param  attributeType  The attribute type for this attribute.
126       * @param  values         The set of values for this attribute.
127       */
128      public LDAPAttribute(String attributeType, List<String> values)
129      {
130        this.attributeType = attributeType;
131    
132        if (values == null)
133        {
134          this.values = new ArrayList<ASN1OctetString>(0);
135        }
136        else
137        {
138          this.values = new ArrayList<ASN1OctetString>(values.size());
139          for (String value : values)
140          {
141            this.values.add(new ASN1OctetString(value));
142          }
143        }
144      }
145    
146    
147    
148      /**
149       * Creates a new LDAP attribute with the provided type and values.
150       *
151       * @param  attributeType  The attribute type for this attribute.
152       * @param  values         The set of values for this attribute.
153       */
154      public LDAPAttribute(String attributeType, ArrayList<ASN1OctetString> values)
155      {
156        this.attributeType = attributeType;
157    
158        if (values == null)
159        {
160          this.values = new ArrayList<ASN1OctetString>(0);
161        }
162        else
163        {
164          this.values = values;
165        }
166      }
167    
168    
169    
170      /**
171       * Creates a new LDAP attribute from the provided attribute.
172       *
173       * @param  attribute  The attribute to use to create this LDAP attribute.
174       */
175      public LDAPAttribute(Attribute attribute)
176      {
177        if (attribute.hasOptions())
178        {
179          StringBuilder attrName = new StringBuilder(attribute.getName());
180          for (String o : attribute.getOptions())
181          {
182            attrName.append(";");
183            attrName.append(o);
184          }
185    
186          this.attributeType = attrName.toString();
187        }
188        else
189        {
190          this.attributeType = attribute.getName();
191        }
192    
193        LinkedHashSet<AttributeValue> attrValues = attribute.getValues();
194        if ((attrValues == null) || attrValues.isEmpty())
195        {
196          values = new ArrayList<ASN1OctetString>(0);
197          return;
198        }
199    
200        values = new ArrayList<ASN1OctetString>(attrValues.size());
201        for (AttributeValue v : attrValues)
202        {
203          values.add(v.getValue().toASN1OctetString());
204        }
205      }
206    
207    
208    
209      /**
210       * Retrieves the attribute type for this attribute.
211       *
212       * @return  The attribute type for this attribute.
213       */
214      public String getAttributeType()
215      {
216        return attributeType;
217      }
218    
219    
220    
221      /**
222       * Specifies the attribute type for this attribute.
223       *
224       * @param  attributeType  The attribute type for this attribute.
225       */
226      public void setAttributeType(String attributeType)
227      {
228        this.attributeType = attributeType;
229      }
230    
231    
232    
233      /**
234       * Retrieves the set of values for this attribute.  The returned list may be
235       * modified by the caller.
236       *
237       * @return  The set of values for this attribute.
238       */
239      public ArrayList<ASN1OctetString> getValues()
240      {
241        return values;
242      }
243    
244    
245    
246      /**
247       * Retrieves a core attribute containing the information for this LDAP
248       * attribute.
249       *
250       * @return  A core attribute containing the information for this LDAP
251       *          attribute.
252       *
253       * @throws  LDAPException  If the provided value is invalid according to the
254       *                         attribute syntax.
255       */
256      public Attribute toAttribute()
257             throws LDAPException
258      {
259        String baseName;
260        String lowerBaseName;
261        int    semicolonPos = attributeType.indexOf(';');
262        LinkedHashSet<String> options;
263        if (semicolonPos > 0)
264        {
265          baseName = attributeType.substring(0, semicolonPos);
266          options = new LinkedHashSet<String>();
267          int nextPos = attributeType.indexOf(';', semicolonPos+1);
268          while (nextPos > 0)
269          {
270            String option = attributeType.substring(semicolonPos+1, nextPos);
271            if (option.length() > 0)
272            {
273              options.add(option);
274            }
275    
276            semicolonPos = nextPos;
277            nextPos = attributeType.indexOf(';', semicolonPos+1);
278          }
279    
280          String option = attributeType.substring(semicolonPos+1);
281          if (option.length() > 0)
282          {
283            options.add(option);
284          }
285        }
286        else
287        {
288          baseName = attributeType;
289          options = new LinkedHashSet<String>(0);
290        }
291        lowerBaseName = toLowerCase(baseName);
292    
293        AttributeType attrType = DirectoryServer.getAttributeType(lowerBaseName);
294        if (attrType == null)
295        {
296          attrType = DirectoryServer.getDefaultAttributeType(lowerBaseName);
297        }
298    
299    
300        LinkedHashSet<AttributeValue> attributeValues =
301             new LinkedHashSet<AttributeValue>(values.size());
302        for (ASN1OctetString value : values)
303        {
304          if (! attributeValues.add(new AttributeValue(attrType, value)))
305          {
306            Message message =
307                ERR_LDAP_ATTRIBUTE_DUPLICATE_VALUES.get(attributeType);
308            throw new LDAPException(
309                    LDAPResultCode.ATTRIBUTE_OR_VALUE_EXISTS, message);
310          }
311        }
312    
313    
314        return new Attribute(attrType, baseName, options, attributeValues);
315      }
316    
317    
318    
319      /**
320       * Retrieves a string representation of this attribute.
321       *
322       * @return  A string representation of this attribute.
323       */
324      public String toString()
325      {
326        StringBuilder buffer = new StringBuilder();
327        toString(buffer);
328        return buffer.toString();
329      }
330    
331    
332    
333      /**
334       * Appends a string representation of this attribute to the provided buffer.
335       *
336       * @param  buffer  The buffer to which the information should be appended.
337       */
338      public void toString(StringBuilder buffer)
339      {
340        buffer.append("LDAPAttribute(type=");
341        buffer.append(attributeType);
342        buffer.append(", values={");
343    
344        if (! values.isEmpty())
345        {
346          Iterator<ASN1OctetString> iterator = values.iterator();
347          iterator.next().toString(buffer);
348          while (iterator.hasNext())
349          {
350            buffer.append(", ");
351            iterator.next().toString(buffer);
352          }
353        }
354    
355        buffer.append("})");
356      }
357    
358    
359    
360      /**
361       * Appends a multi-line string representation of this LDAP attribute to the
362       * provided buffer.
363       *
364       * @param  buffer  The buffer to which the information should be appended.
365       * @param  indent  The number of spaces from the margin that the lines should
366       *                 be indented.
367       */
368      public void toString(StringBuilder buffer, int indent)
369      {
370        StringBuilder indentBuf = new StringBuilder(indent);
371        for (int i=0 ; i < indent; i++)
372        {
373          indentBuf.append(' ');
374        }
375    
376        buffer.append(indentBuf);
377        buffer.append("LDAP Attribute");
378        buffer.append(EOL);
379    
380        buffer.append(indentBuf);
381        buffer.append("  Attribute Type:  ");
382        buffer.append(attributeType);
383        buffer.append(EOL);
384    
385        buffer.append("  Attribute Values:");
386        buffer.append(EOL);
387    
388        for (ASN1OctetString value : values)
389        {
390          value.toString(buffer, indent+4);
391        }
392      }
393    }
394