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.data; 019 020import com.unboundid.scim.marshal.Marshaller; 021import com.unboundid.scim.schema.AttributeDescriptor; 022import com.unboundid.scim.schema.ResourceDescriptor; 023import com.unboundid.scim.sdk.InvalidResourceException; 024import com.unboundid.scim.sdk.SCIMAttribute; 025import com.unboundid.scim.sdk.SCIMAttributeValue; 026import com.unboundid.scim.sdk.SCIMConstants; 027import com.unboundid.scim.sdk.SCIMObject; 028import com.unboundid.scim.sdk.SCIMResponse; 029 030import java.io.OutputStream; 031import java.util.ArrayList; 032import java.util.Collection; 033 034/** 035 * This class represents a SCIM resource. It could also be sub-typed for 036 * specific resource types (ie. Users or Groups) that provide convenience 037 * methods for accessing specific attribute values. 038 */ 039public class BaseResource implements SCIMResponse 040{ 041 /** 042 * A <code>ResourceFactory</code> for creating <code>BaseResource</code> 043 * instances. 044 */ 045 public static final ResourceFactory<BaseResource> BASE_RESOURCE_FACTORY = 046 new ResourceFactory<BaseResource>() { 047 /** 048 * {@inheritDoc} 049 */ 050 public BaseResource createResource( 051 final ResourceDescriptor resourceDescriptor, 052 final SCIMObject scimObject) { 053 return new BaseResource(resourceDescriptor, scimObject); 054 } 055 }; 056 057 private final ResourceDescriptor resourceDescriptor; 058 private final SCIMObject scimObject; 059 060 /** 061 * Construct a <code>BaseResource</code> with the specified 062 * <code>ResourceDescriptor</code> and backed by the given 063 * <code>SCIMObject</code>. 064 * 065 * @param resourceDescriptor The resource descriptor for this SCIM resource. 066 * @param scimObject The <code>SCIMObject</code> containing all the 067 * SCIM attributes and their values. 068 */ 069 public BaseResource(final ResourceDescriptor resourceDescriptor, 070 final SCIMObject scimObject) 071 { 072 this.resourceDescriptor = resourceDescriptor; 073 this.scimObject = scimObject; 074 } 075 076 /** 077 * Construct an empty <code>BaseResource</code> with the specified 078 * <code>ResourceDescriptor</code>. 079 * 080 * @param resourceDescriptor The resource descriptor for this SCIM resource. 081 */ 082 public BaseResource(final ResourceDescriptor resourceDescriptor) 083 { 084 this.resourceDescriptor = resourceDescriptor; 085 this.scimObject = new SCIMObject(); 086 } 087 088 /** 089 * Retrieves the <code>ResourceDescriptor</code> for this resource. 090 * 091 * @return The <code>ResourceDescriptor</code> for this resource. 092 */ 093 public ResourceDescriptor getResourceDescriptor() { 094 return resourceDescriptor; 095 } 096 097 /** 098 * Retrieves the <code>SCIMObject</code> wrapped by this resource. 099 * 100 * @return The <code>SCIMObject</code> wrapped by this resource. 101 */ 102 public SCIMObject getScimObject() { 103 return scimObject; 104 } 105 106 /** 107 * Retrieves the unique identifier for the SCIM Resource as defined by 108 * the Service Provider. 109 * 110 * @return The unique identifier for the SCIM Resource as defined by 111 * the Service Provider. 112 */ 113 public String getId() 114 { 115 return getSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, "id", 116 AttributeValueResolver.STRING_RESOLVER); 117 } 118 119 /** 120 * Sets the unique identifier for the SCIM Resource. 121 * 122 * @param id The unique identifier for the SCIM Resource. 123 */ 124 public void setId(final String id) 125 { 126 try { 127 setSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, "id", 128 AttributeValueResolver.STRING_RESOLVER, id); 129 } catch (InvalidResourceException e) { 130 // This should never happen as these are core attributes... 131 throw new RuntimeException(e); 132 } 133 } 134 135 /** 136 * Retrieves the unique identifier for the Resource as defined by the 137 * Service Consumer. 138 * 139 * @return The unique identifier for the Resource as defined by the Service 140 * Consumer. 141 */ 142 public String getExternalId() 143 { 144 return getSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, 145 "externalId", AttributeValueResolver.STRING_RESOLVER); 146 } 147 148 /** 149 * Sets the unique identifier for the Resource as defined by the Service 150 * Consumer. 151 * 152 * @param externalId The unique identifier for the Resource as defined by the 153 * Service Consumer. 154 */ 155 public void setExternalId(final String externalId) 156 { 157 try { 158 setSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, "externalId", 159 AttributeValueResolver.STRING_RESOLVER, externalId); 160 } catch (InvalidResourceException e) { 161 // This should never happen as these are core attributes... 162 throw new RuntimeException(e); 163 } 164 } 165 166 167 /** 168 * Retrieves the metadata about the resource. 169 * 170 * @return The metadata about the resource. 171 */ 172 public Meta getMeta() 173 { 174 return getSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, "meta", 175 Meta.META_RESOLVER); 176 } 177 178 /** 179 * Sets the metadata about the resource. 180 * @param meta The metadata about the resource. 181 */ 182 public void setMeta(final Meta meta) 183 { 184 try { 185 setSingularAttributeValue(SCIMConstants.SCHEMA_URI_CORE, "meta", 186 Meta.META_RESOLVER, meta); 187 } catch (InvalidResourceException e) { 188 // This should never happen as these are core attributes... 189 throw new RuntimeException(e); 190 } 191 } 192 193 /** 194 * Retrieves a singular attribute value. 195 * 196 * @param <T> The type of the resolved instance representing the value of 197 * sub-attribute. 198 * @param schema The schema URI of the attribute value to retrieve. 199 * @param name The name of the attribute value to retrieve. 200 * @param resolver The <code>AttributeValueResolver</code> the should be used 201 * to resolve the value to an instance. 202 * @return The resolved value instance or <code>null</code> if the specified 203 * attribute does not exist. 204 */ 205 public <T> T getSingularAttributeValue( 206 final String schema, final String name, 207 final AttributeValueResolver<T> resolver) 208 { 209 SCIMAttribute attribute = scimObject.getAttribute(schema, name); 210 if(attribute != null) 211 { 212 SCIMAttributeValue value = attribute.getValue(); 213 if(value != null) 214 { 215 return resolver.toInstance(value); 216 } 217 } 218 return null; 219 } 220 221 /** 222 * Sets a singular attribute value. 223 * 224 * @param <T> The type of the resolved instance representing the value of 225 * sub-attribute. 226 * @param schema The schema URI of the attribute value to retrieve. 227 * @param name The name of the attribute value to retrieve. 228 * @param resolver The <code>AttributeValueResolver</code> the should be used 229 * to resolve the instance to attribute value. 230 * @param value The value instance. 231 * @throws InvalidResourceException if the attribute is not defined by the 232 * resource. 233 */ 234 public <T> void setSingularAttributeValue( 235 final String schema, final String name, 236 final AttributeValueResolver<T> resolver, final T value) 237 throws InvalidResourceException 238 { 239 if(value == null) 240 { 241 scimObject.removeAttribute(schema, name); 242 return; 243 } 244 245 AttributeDescriptor attributeDescriptor = 246 getResourceDescriptor().getAttribute(schema, name); 247 248 scimObject.setAttribute(SCIMAttribute.create( 249 attributeDescriptor, resolver.fromInstance(attributeDescriptor, 250 value))); 251 } 252 253 /** 254 * Retrieves a multi-valued attribute value. 255 * 256 * @param <T> The type of the resolved instance representing the value of 257 * sub-attribute. 258 * @param schema The schema URI of the attribute value to retrieve. 259 * @param name The name of the attribute value to retrieve. 260 * @param resolver The <code>AttributeValueResolver</code> the should be used 261 * to resolve the value to an instance. 262 * @return The collection of resolved value instances or <code>null</code> if 263 * the specified attribute does not exist. 264 */ 265 public <T> Collection<T> getAttributeValues( 266 final String schema, final String name, 267 final AttributeValueResolver<T> resolver) 268 { 269 SCIMAttribute attribute = scimObject.getAttribute(schema, name); 270 if(attribute != null) 271 { 272 SCIMAttributeValue[] values = attribute.getValues(); 273 if(values != null) 274 { 275 Collection<T> entries = new ArrayList<T>(values.length); 276 for(SCIMAttributeValue v : values) 277 { 278 entries.add(resolver.toInstance(v)); 279 } 280 return entries; 281 } 282 } 283 return null; 284 } 285 286 /** 287 * Sets a multi-valued attribute value. 288 * 289 * @param <T> The type of the resolved instance representing the value of 290 * sub-attribute. 291 * @param schema The schema URI of the attribute value to retrieve. 292 * @param name The name of the attribute value to retrieve. 293 * @param resolver The <code>AttributeValueResolver</code> the should be used 294 * to resolve the instance to attribute value. 295 * @param values The value instances. 296 * @throws InvalidResourceException if the attribute is not defined by the 297 * resource. 298 */ 299 public <T> void setAttributeValues( 300 final String schema, final String name, 301 final AttributeValueResolver<T> resolver, final Collection<T> values) 302 throws InvalidResourceException 303 { 304 if(values == null) 305 { 306 scimObject.removeAttribute(schema, name); 307 return; 308 } 309 310 AttributeDescriptor attributeDescriptor = 311 getResourceDescriptor().getAttribute(schema, name); 312 313 SCIMAttributeValue[] entries = new SCIMAttributeValue[values.size()]; 314 315 int i = 0; 316 for(T value : values) 317 { 318 entries[i++] = resolver.fromInstance(attributeDescriptor, value); 319 } 320 321 scimObject.setAttribute( 322 SCIMAttribute.create(attributeDescriptor, entries)); 323 } 324 325 /** 326 * {@inheritDoc} 327 */ 328 public void marshal(final Marshaller marshaller, 329 final OutputStream outputStream) 330 throws Exception { 331 marshaller.marshal(this, outputStream); 332 } 333 334 /** 335 * {@inheritDoc} 336 */ 337 @Override 338 public boolean equals(final Object o) { 339 if (this == o) { 340 return true; 341 } 342 if (!(o instanceof BaseResource)) { 343 return false; 344 } 345 346 BaseResource that = (BaseResource) o; 347 348 if (!resourceDescriptor.equals(that.resourceDescriptor)) { 349 return false; 350 } 351 if (!scimObject.equals(that.scimObject)) { 352 return false; 353 } 354 355 return true; 356 } 357 358 /** 359 * {@inheritDoc} 360 */ 361 @Override 362 public int hashCode() { 363 int result = resourceDescriptor.hashCode(); 364 result = 31 * result + scimObject.hashCode(); 365 return result; 366 } 367 368 369 370 /** 371 * {@inheritDoc} 372 */ 373 @Override 374 public String toString() 375 { 376 final StringBuilder sb = new StringBuilder(); 377 sb.append("BaseResource"); 378 sb.append("{resource=").append(resourceDescriptor.getSchema()); 379 sb.append(SCIMConstants.SEPARATOR_CHAR_QUALIFIED_ATTRIBUTE); 380 sb.append(resourceDescriptor.getName()); 381 sb.append(", scimObject=").append(scimObject); 382 sb.append('}'); 383 return sb.toString(); 384 } 385}