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}