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.data;
019
020 import com.unboundid.scim.marshal.Marshaller;
021 import com.unboundid.scim.schema.AttributeDescriptor;
022 import com.unboundid.scim.schema.ResourceDescriptor;
023 import com.unboundid.scim.sdk.InvalidResourceException;
024 import com.unboundid.scim.sdk.SCIMAttribute;
025 import com.unboundid.scim.sdk.SCIMAttributeValue;
026 import com.unboundid.scim.sdk.SCIMConstants;
027 import com.unboundid.scim.sdk.SCIMObject;
028 import com.unboundid.scim.sdk.SCIMResponse;
029
030 import java.io.OutputStream;
031 import java.util.ArrayList;
032 import 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 */
039 public 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 }