001/* 002 * Copyright 2011-2013 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 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}