001/*
002 * Copyright 2011-2016 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
018package com.unboundid.scim.sdk;
019
020import com.unboundid.scim.data.AttributeValueResolver;
021import com.unboundid.scim.schema.AttributeDescriptor;
022
023import javax.xml.bind.DatatypeConverter;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.Date;
028import java.util.LinkedHashMap;
029import java.util.Map;
030
031
032
033/**
034 * This class represents a System for Cross-Domain Identity Management (SCIM)
035 * attribute 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 */
042public abstract class SCIMAttributeValue
043{
044  /**
045   * Create a new simple attribute value of the specified data type.
046   *
047   * @param dataType  The data type of the value.
048   * @param value     The string representation of the value.
049   *
050   * @return  The new simple attribute value.
051   */
052  public static SCIMAttributeValue createValue(
053      final AttributeDescriptor.DataType dataType,
054      final String value)
055  {
056    switch (dataType)
057    {
058      case BINARY:
059        return createBinaryValue(DatatypeConverter.parseBase64Binary(value));
060      default:
061        return createStringValue(value);
062    }
063  }
064
065
066
067  /**
068   * Create a new simple String attribute value.
069   *
070   * @param value  The String attribute value.
071   *
072   * @return  The new simple attribute.
073   */
074  public static SCIMAttributeValue createStringValue(final String value)
075  {
076    return new SimpleSCIMAttributeValue(new SimpleValue(value));
077  }
078
079
080
081  /**
082   * Create a new simple Boolean attribute value.
083   *
084   * @param value  The Boolean attribute value.
085   *
086   * @return  The new simple attribute.
087   */
088  public static SCIMAttributeValue createBooleanValue(final Boolean value)
089  {
090    return new SimpleSCIMAttributeValue(new SimpleValue(value));
091  }
092
093
094
095  /**
096   * Create a new simple Date attribute value.
097   *
098   * @param value  The Date attribute value.
099   *
100   * @return  The new simple attribute.
101   */
102  public static SCIMAttributeValue createDateValue(final Date value)
103  {
104    return new SimpleSCIMAttributeValue(new SimpleValue(value));
105  }
106
107
108
109  /**
110   * Create a new simple binary attribute value.
111   *
112   * @param value  The binary attribute value.
113   *
114   * @return  The new simple attribute.
115   */
116  public static SCIMAttributeValue createBinaryValue(final byte[] value)
117  {
118    return new SimpleSCIMAttributeValue(new SimpleValue(value));
119  }
120
121
122  /**
123   * Create a new simple attribute value.
124   * @param simpleValue  The SimpleValue attribute value.
125   * @return  The new Simple attribute.
126   */
127  public static SCIMAttributeValue createSimpleValue(
128      final SimpleValue simpleValue)
129  {
130    return new SimpleSCIMAttributeValue(simpleValue);
131  }
132
133
134  /**
135   * Retrieves the value of a sub-attribute.
136   *
137   * @param <T>          The type of the resolved instance representing the
138   *                     value of sub-attribute.
139   * @param name         The name of the sub-attribute.
140   * @param resolver     The <code>AttributeValueResolver</code> that should
141   *                     be used to resolve the value into an instance.
142   * @return             The resolved instance representing the value of
143   *                     sub-attribute.
144   */
145  public <T> T getSubAttributeValue(final String name,
146                                    final AttributeValueResolver<T> resolver)
147  {
148    SCIMAttribute attribute = getAttribute(name);
149    if(attribute != null)
150    {
151      SCIMAttributeValue v = attribute.getValue();
152      if(v != null)
153      {
154        return resolver.toInstance(v);
155      }
156    }
157    return null;
158  }
159
160  /**
161   * Retrieves the value of a multi-valued sub-attribute value.
162   *
163   * @param <T>    The type of the resolved instance representing the value of
164   *               sub-attribute.
165   * @param name The name of the attribute value to retrieve.
166   * @param resolver The <code>AttributeValueResolver</code> the should be used
167   *                 to resolve the value to an instance.
168   * @return The collection of resolved value instances or <code>null</code> if
169   *         the specified attribute does not exist.
170   */
171  public <T> Collection<T> getSubAttributeValues(
172      final String name, final AttributeValueResolver<T> resolver)
173  {
174    SCIMAttribute attribute = getAttribute(name);
175    if(attribute != null)
176    {
177      SCIMAttributeValue[] values = attribute.getValues();
178      if(values != null)
179      {
180        Collection<T> entries = new ArrayList<T>(values.length);
181        for(SCIMAttributeValue v : values)
182        {
183          entries.add(resolver.toInstance(v));
184        }
185        return entries;
186      }
187    }
188    return null;
189  }
190
191
192
193  /**
194   * Create a new complex attribute value from the provided attributes.
195   *
196   * @param attributes  The attributes comprising the complex value.
197   *
198   * @return  The new complex attribute.
199   */
200  public static SCIMAttributeValue createComplexValue(
201      final SCIMAttribute ... attributes)
202  {
203    final Map<String,SCIMAttribute> map =
204        new LinkedHashMap<String, SCIMAttribute>();
205    for (final SCIMAttribute a : attributes)
206    {
207      final String lowerCaseName = StaticUtils.toLowerCase(a.getName());
208      if (map.containsKey(lowerCaseName))
209      {
210        throw new RuntimeException("Duplicate attribute " + a.getName() +
211                                   " in complex attribute value");
212      }
213      map.put(lowerCaseName, a);
214    }
215    return new ComplexSCIMAttributeValue(Collections.unmodifiableMap(map));
216  }
217
218
219
220  /**
221   * Create a new complex attribute value from a collection of attributes.
222   *
223   * @param attributes  The attributes comprising the complex value.
224   *
225   * @return  The new complex attribute value.
226   */
227  public static SCIMAttributeValue createComplexValue(
228      final Collection<SCIMAttribute> attributes)
229  {
230    final Map<String,SCIMAttribute> map =
231        new LinkedHashMap<String, SCIMAttribute>();
232    for (final SCIMAttribute a : attributes)
233    {
234      final String lowerCaseName = StaticUtils.toLowerCase(a.getName());
235      if (map.containsKey(lowerCaseName))
236      {
237        throw new RuntimeException("Duplicate attribute " + a.getName() +
238                                   " in complex attribute value");
239      }
240      map.put(lowerCaseName, a);
241    }
242    return new ComplexSCIMAttributeValue(Collections.unmodifiableMap(map));
243  }
244
245
246
247  /**
248   * Determines whether this attribute value is simple or complex.
249   *
250   * @return  {@code true} if this attribute value is complex, or {@code false}
251   *          otherwise.
252   */
253  public abstract boolean isComplex();
254
255
256
257  /**
258   * Retrieves the simple value, or {@code null} if the attribute value is
259   * complex.
260   *
261   * @return  The simple value, or {@code null} if the attribute value is
262   * complex.
263   */
264  public abstract SimpleValue getValue();
265
266
267
268  /**
269   * Retrieves the simple String value, or {@code null} if the attribute
270   * value is complex.
271   *
272   * @return  The simple String value, or {@code null} if the attribute
273   *          value is complex.
274   */
275  public String getStringValue()
276  {
277    SimpleValue value = getValue();
278    if(value == null)
279    {
280      return null;
281    }
282    return value.getStringValue();
283  }
284
285
286
287  /**
288   * Retrieves the simple Boolean value, or {@code null} if the attribute
289   * value is complex.
290   *
291   * @return  The simple Boolean value, or {@code null} if the attribute
292   *          value is complex.
293   */
294  public Boolean getBooleanValue()
295  {
296    SimpleValue value = getValue();
297    if(value == null)
298    {
299      return null;
300    }
301    return value.getBooleanValue();
302  }
303
304
305
306  /**
307   * Retrieves the simple Decimal value, or {@code null} if the attribute
308   * value is complex.
309   *
310   * @return  The simple Decimal value, or {@code null} if the attribute
311   *          value is complex.
312   */
313  public Double getDecimalValue()
314  {
315    SimpleValue value = getValue();
316    if(value == null)
317    {
318      return null;
319    }
320    return value.getDoubleValue();
321  }
322
323
324
325  /**
326   * Retrieves the simple Long value, or {@code null} if the attribute
327   * value is complex.
328   *
329   * @return  The simple Long value, or {@code null} if the attribute
330   *          value is complex.
331   */
332  public Long getIntegerValue()
333  {
334    SimpleValue value = getValue();
335    if(value == null)
336    {
337      return null;
338    }
339    return value.getLongValue();
340  }
341
342
343
344  /**
345   * Retrieves the simple Date value, or {@code null} if the attribute
346   * value is complex.
347   *
348   * @return  The simple Date value, or {@code null} if the attribute
349   *          value is complex.
350   */
351  public Date getDateValue()
352  {
353    SimpleValue value = getValue();
354    if(value == null)
355    {
356      return null;
357    }
358    return value.getDateValue();
359  }
360
361
362
363  /**
364   * Retrieves the simple Binary value, or {@code null} if the attribute
365   * value is complex.
366   *
367   * @return  The simple Binary value, or {@code null} if the attribute
368   *          value is complex.
369   */
370  public byte[] getBinaryValue()
371  {
372    SimpleValue value = getValue();
373    if(value == null)
374    {
375      return null;
376    }
377    return value.getBinaryValue();
378  }
379
380
381
382  /**
383   * Retrieves the attributes comprising the complex value, keyed by the lower
384   * case name of the attribute, or {@code null} if the attribute value is
385   * simple.
386   *
387   * @return  The attributes comprising the complex value.
388   */
389  public abstract Map<String, SCIMAttribute> getAttributes();
390
391
392
393  /**
394   * Retrieves the attribute with the provided name from the complex value,
395   * or {@code null} if there is no such attribute or the attribute value is
396   * simple.
397   *
398   * @param attributeName  The name of the desired attribute.
399   *
400   * @return  The attribute with the provided name, or {@code null} if there
401   *          is no such attribute or the attribute value is simple.
402   */
403  public SCIMAttribute getAttribute(final String attributeName)
404  {
405    Map<String, SCIMAttribute> attributes = getAttributes();
406    if (attributes != null)
407    {
408      return attributes.get(StaticUtils.toLowerCase(attributeName));
409    }
410    else
411    {
412      return null;
413    }
414  }
415
416
417
418  /**
419   * Indicates whether a complex value has an attribute with the provided name.
420   *
421   * @param attributeName  The attribute name for which to make the
422   *                       determination.
423   *
424   * @return  {@code true} if there is an attribute with the provided name,
425   *          {@code false} if there is no such attribute or this attribute
426   *          value is simple.
427   */
428  public boolean hasAttribute(final String attributeName)
429  {
430    Map<String, SCIMAttribute> attributes = getAttributes();
431    if (attributes != null)
432    {
433      return attributes.containsKey(StaticUtils.toLowerCase(attributeName));
434    }
435    else
436    {
437      return false;
438    }
439  }
440
441}