001    /*
002     * Copyright 2011-2012 UnboundID Corp.
003     *
004     * This program is free software; you can redistribute it and/or modify
005     * it under the terms of the GNU General Public License (GPLv2 only)
006     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007     * as published by the Free Software Foundation.
008     *
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, see <http://www.gnu.org/licenses>.
016     */
017    
018    package com.unboundid.scim.sdk;
019    
020    import com.unboundid.scim.data.AttributeValueResolver;
021    import com.unboundid.scim.schema.AttributeDescriptor;
022    
023    import javax.xml.bind.DatatypeConverter;
024    import java.util.ArrayList;
025    import java.util.Collection;
026    import java.util.Collections;
027    import java.util.Date;
028    import java.util.LinkedHashMap;
029    import java.util.Map;
030    
031    
032    
033    /**
034     * This class represents a Simple Cloud Identity Management (SCIM) attribute
035     * value. Values are categorized as either Simple or Complex.
036     *
037     * <ul>
038     * <li>Simple values can be String, Boolean, DateTime, Integer or Binary.</li>
039     * <li>Complex values are composed of a set of subordinate SCIM attributes.</li>
040     * </ul>
041     */
042    public final class SCIMAttributeValue
043    {
044      /**
045       * The simple attribute value, or {@code null} if the attribute value is
046       * complex.
047       */
048      private final SimpleValue value;
049    
050      /**
051       * The attributes comprising the complex value, keyed by the lower case
052       * name of the attribute, or {@code null} if the attribute value is simple.
053       */
054      private final Map<String,SCIMAttribute> attributes;
055    
056    
057    
058      /**
059       * Create a new instance of a SCIM attribute value.
060       *
061       * @param value  The simple value.
062       */
063      public SCIMAttributeValue(final SimpleValue value)
064      {
065        this.value      = value;
066        this.attributes = null;
067      }
068    
069    
070    
071      /**
072       * Create a new instance of a SCIM complex attribute value.
073       *
074       * @param attributes  The attributes comprising the complex value, keyed by
075       *                    the name of the attribute.
076       */
077      private SCIMAttributeValue(final Map<String,SCIMAttribute> attributes)
078      {
079        this.value = null;
080        this.attributes = attributes;
081      }
082    
083    
084    
085      /**
086       * Create a new simple attribute value of the specified data type.
087       *
088       * @param dataType  The data type of the value.
089       * @param value     The string representation of the value.
090       *
091       * @return  The new simple attribute value.
092       */
093      public static SCIMAttributeValue createValue(
094          final AttributeDescriptor.DataType dataType,
095          final String value)
096      {
097        switch (dataType)
098        {
099          case BINARY:
100            return createBinaryValue(DatatypeConverter.parseBase64Binary(value));
101          default:
102            return createStringValue(value);
103        }
104      }
105    
106    
107    
108      /**
109       * Create a new simple String attribute value.
110       *
111       * @param value  The String attribute value.
112       *
113       * @return  The new simple attribute.
114       */
115      public static SCIMAttributeValue createStringValue(final String value)
116      {
117        return new SCIMAttributeValue(new SimpleValue(value));
118      }
119    
120    
121    
122      /**
123       * Create a new simple Boolean attribute value.
124       *
125       * @param value  The Boolean attribute value.
126       *
127       * @return  The new simple attribute.
128       */
129      public static SCIMAttributeValue createBooleanValue(final Boolean value)
130      {
131        return new SCIMAttributeValue(new SimpleValue(value));
132      }
133    
134    
135    
136      /**
137       * Create a new simple Date attribute value.
138       *
139       * @param value  The Date attribute value.
140       *
141       * @return  The new simple attribute.
142       */
143      public static SCIMAttributeValue createDateValue(final Date value)
144      {
145        return new SCIMAttributeValue(new SimpleValue(value));
146      }
147    
148    
149    
150      /**
151       * Create a new simple binary attribute value.
152       *
153       * @param value  The binary attribute value.
154       *
155       * @return  The new simple attribute.
156       */
157      public static SCIMAttributeValue createBinaryValue(final byte[] value)
158      {
159        return new SCIMAttributeValue(new SimpleValue(value));
160      }
161    
162      /**
163       * Retrieves the value of a sub-attribute.
164       *
165       * @param <T>          The type of the resolved instance representing the
166       *                     value of sub-attribute.
167       * @param name         The name of the sub-attribute.
168       * @param resolver     The <code>AttributeValueResolver</code> that should
169       *                     be used to resolve the value into an instance.
170       * @return             The resolved instance representing the value of
171       *                     sub-attribute.
172       */
173      public <T> T getSubAttributeValue(final String name,
174                                        final AttributeValueResolver<T> resolver)
175      {
176        SCIMAttribute attribute = getAttribute(name);
177        if(attribute != null)
178        {
179          SCIMAttributeValue v = attribute.getValue();
180          if(v != null)
181          {
182            return resolver.toInstance(v);
183          }
184        }
185        return null;
186      }
187    
188      /**
189       * Retrieves the value of a multi-valued sub-attribute value.
190       *
191       * @param <T>    The type of the resolved instance representing the value of
192       *               sub-attribute.
193       * @param name The name of the attribute value to retrieve.
194       * @param resolver The <code>AttributeValueResolver</code> the should be used
195       *                 to resolve the value to an instance.
196       * @return The collection of resolved value instances or <code>null</code> if
197       *         the specified attribute does not exist.
198       */
199      public <T> Collection<T> getSubAttributeValues(
200          final String name, final AttributeValueResolver<T> resolver)
201      {
202        SCIMAttribute attribute = getAttribute(name);
203        if(attribute != null)
204        {
205          SCIMAttributeValue[] values = attribute.getValues();
206          if(values != null)
207          {
208            Collection<T> entries = new ArrayList<T>(values.length);
209            for(SCIMAttributeValue v : values)
210            {
211              entries.add(resolver.toInstance(v));
212            }
213            return entries;
214          }
215        }
216        return null;
217      }
218    
219    
220    
221      /**
222       * {@inheritDoc}
223       */
224      @Override
225      public String toString()
226      {
227        final StringBuilder sb = new StringBuilder();
228        sb.append("SCIMAttributeValue{");
229        if (value != null)
230        {
231          sb.append("value=").append(value);
232        }
233        else
234        {
235          sb.append("attributes=").append(attributes);
236        }
237        sb.append('}');
238        return sb.toString();
239      }
240    
241    
242    
243      /**
244       * Create a new complex attribute value from the provided attributes.
245       *
246       * @param attributes  The attributes comprising the complex value.
247       *
248       * @return  The new complex attribute.
249       */
250      public static SCIMAttributeValue createComplexValue(
251          final SCIMAttribute ... attributes)
252      {
253        final Map<String,SCIMAttribute> map =
254            new LinkedHashMap<String, SCIMAttribute>();
255        for (final SCIMAttribute a : attributes)
256        {
257          final String lowerCaseName = StaticUtils.toLowerCase(a.getName());
258          if (map.containsKey(lowerCaseName))
259          {
260            throw new RuntimeException("Duplicate attribute " + a.getName() +
261                                       " in complex attribute value");
262          }
263          map.put(lowerCaseName, a);
264        }
265        return new SCIMAttributeValue(Collections.unmodifiableMap(map));
266      }
267    
268    
269    
270      /**
271       * Create a new complex attribute value from a collection of attributes.
272       *
273       * @param attributes  The attributes comprising the complex value.
274       *
275       * @return  The new complex attribute value.
276       */
277      public static SCIMAttributeValue createComplexValue(
278          final Collection<SCIMAttribute> attributes)
279      {
280        final Map<String,SCIMAttribute> map =
281            new LinkedHashMap<String, SCIMAttribute>();
282        for (final SCIMAttribute a : attributes)
283        {
284          final String lowerCaseName = StaticUtils.toLowerCase(a.getName());
285          if (map.containsKey(lowerCaseName))
286          {
287            throw new RuntimeException("Duplicate attribute " + a.getName() +
288                                       " in complex attribute value");
289          }
290          map.put(lowerCaseName, a);
291        }
292        return new SCIMAttributeValue(Collections.unmodifiableMap(map));
293      }
294    
295    
296    
297      /**
298       * Determines whether this attribute value is simple or complex.
299       *
300       * @return  {@code true} if this attribute value is complex, or {@code false}
301       *          otherwise.
302       */
303      public boolean isComplex()
304      {
305        return this.value == null;
306      }
307    
308    
309    
310      /**
311       * Retrieves the simple value, or {@code null} if the attribute value is
312       * complex.
313       *
314       * @return  The simple value, or {@code null} if the attribute value is
315       * complex.
316       */
317      public SimpleValue getValue()
318      {
319        return value;
320      }
321    
322    
323    
324      /**
325       * Retrieves the simple String value, or {@code null} if the attribute
326       * value is complex.
327       *
328       * @return  The simple String value, or {@code null} if the attribute
329       *          value is complex.
330       */
331      public String getStringValue()
332      {
333        return value.getStringValue();
334      }
335    
336    
337    
338      /**
339       * Retrieves the simple Boolean value, or {@code null} if the attribute
340       * value is complex.
341       *
342       * @return  The simple Boolean value, or {@code null} if the attribute
343       *          value is complex.
344       */
345      public Boolean getBooleanValue()
346      {
347        return value.getBooleanValue();
348      }
349    
350    
351    
352      /**
353       * Retrieves the simple Decimal value, or {@code null} if the attribute
354       * value is complex.
355       *
356       * @return  The simple Decimal value, or {@code null} if the attribute
357       *          value is complex.
358       */
359      public Double getDecimalValue()
360      {
361        return value.getDoubleValue();
362      }
363    
364    
365    
366      /**
367       * Retrieves the simple Long value, or {@code null} if the attribute
368       * value is complex.
369       *
370       * @return  The simple Long value, or {@code null} if the attribute
371       *          value is complex.
372       */
373      public Long getIntegerValue()
374      {
375        return value.getLongValue();
376      }
377    
378    
379    
380      /**
381       * Retrieves the simple Date value, or {@code null} if the attribute
382       * value is complex.
383       *
384       * @return  The simple Date value, or {@code null} if the attribute
385       *          value is complex.
386       */
387      public Date getDateValue()
388      {
389        return value.getDateValue();
390      }
391    
392    
393    
394      /**
395       * Retrieves the simple Binary value, or {@code null} if the attribute
396       * value is complex.
397       *
398       * @return  The simple Binary value, or {@code null} if the attribute
399       *          value is complex.
400       */
401      public byte[] getBinaryValue()
402      {
403        return value.getBinaryValue();
404      }
405    
406    
407    
408      /**
409       * Retrieves the attributes comprising the complex value, keyed by the lower
410       * case name of the attribute, or {@code null} if the attribute value is
411       * simple.
412       *
413       * @return  The attributes comprising the complex value.
414       */
415      public Map<String, SCIMAttribute> getAttributes()
416      {
417        return attributes;
418      }
419    
420    
421    
422      /**
423       * Retrieves the attribute with the provided name from the complex value,
424       * or {@code null} if there is no such attribute or the attribute value is
425       * simple.
426       *
427       * @param attributeName  The name of the desired attribute.
428       *
429       * @return  The attribute with the provided name, or {@code null} if there
430       *          is no such attribute or the attribute value is simple.
431       */
432      public SCIMAttribute getAttribute(final String attributeName)
433      {
434        if (attributes != null)
435        {
436          return attributes.get(StaticUtils.toLowerCase(attributeName));
437        }
438        else
439        {
440          return null;
441        }
442      }
443    
444    
445    
446      /**
447       * Indicates whether a complex value has an attribute with the provided name.
448       *
449       * @param attributeName  The attribute name for which to make the
450       *                       determination.
451       *
452       * @return  {@code true} if there is an attribute with the provided name,
453       *          {@code false} if there is no such attribute or this attribute
454       *          value is simple.
455       */
456      public boolean hasAttribute(final String attributeName)
457      {
458        if (attributes != null)
459        {
460          return attributes.containsKey(StaticUtils.toLowerCase(attributeName));
461        }
462        else
463        {
464          return false;
465        }
466      }
467    
468    
469      /**
470       * {@inheritDoc}
471       */
472      @Override
473      public boolean equals(final Object o) {
474        if (this == o) {
475          return true;
476        }
477        if (o == null || getClass() != o.getClass()) {
478          return false;
479        }
480    
481        SCIMAttributeValue that = (SCIMAttributeValue) o;
482    
483        if (attributes != null ? !attributes.equals(that.attributes) :
484            that.attributes != null) {
485          return false;
486        }
487        if (value != null ? !value.equals(that.value) : that.value != null) {
488          return false;
489        }
490    
491        return true;
492      }
493    
494    
495      /**
496       * {@inheritDoc}
497       */
498      @Override
499      public int hashCode() {
500        int result = value != null ? value.hashCode() : 0;
501        result = 31 * result + (attributes != null ? attributes.hashCode() : 0);
502        return result;
503      }
504    }