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 }