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.schema;
019
020import com.unboundid.scim.sdk.InvalidResourceException;
021import com.unboundid.scim.sdk.SCIMAttribute;
022import com.unboundid.scim.sdk.SCIMAttributeValue;
023import com.unboundid.scim.sdk.SCIMConstants;
024import com.unboundid.scim.sdk.SCIMObject;
025
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.LinkedHashMap;
029import java.util.Map;
030
031import static com.unboundid.scim.sdk.StaticUtils.toLowerCase;
032
033/**
034 * Contains the resources and their attributes defined in
035 * Core Schema 1.1.
036 */
037public class CoreSchema
038{
039  //// 5.  SCIM Core Schema ////
040
041  //// 5.1.  Common Schema Attributes ////
042  /** ID attribute. */
043  public static final AttributeDescriptor ID =
044      AttributeDescriptor.createAttribute("id",
045          AttributeDescriptor.DataType.STRING,
046          "Unique identifier for the SCIM Resource as defined by the " +
047              "Service Provider",
048          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
049
050  /** ExternalID attribute. */
051  public static final AttributeDescriptor EXTERNAL_ID =
052      AttributeDescriptor.createAttribute("externalId",
053          AttributeDescriptor.DataType.STRING,
054          "Unique identifier for the Resource as defined by the " +
055              "Service Consumer",
056          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
057
058  /** Created meta attribute. */
059  public static final AttributeDescriptor META_CREATED =
060      AttributeDescriptor.createSubAttribute("created",
061          AttributeDescriptor.DataType.DATETIME,
062          "The DateTime the Resource was added to the Service Provider",
063          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
064
065  /** Last modified meta attribute. */
066  public static final AttributeDescriptor META_LAST_MODIFIED =
067      AttributeDescriptor.createSubAttribute("lastModified",
068          AttributeDescriptor.DataType.DATETIME,
069          "The most recent DateTime the details of this Resource were " +
070              "updated at the Service Provider",
071          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
072
073  /** Location meta attribute. */
074  public static final AttributeDescriptor META_LOCATION =
075      AttributeDescriptor.createSubAttribute("location",
076          AttributeDescriptor.DataType.STRING,
077          "The URI of the Resource being returned",
078          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
079
080  /** Version meta attribute. */
081  public static final AttributeDescriptor META_VERSION =
082      AttributeDescriptor.createSubAttribute("version",
083          AttributeDescriptor.DataType.STRING,
084          "The version of the Resource being returned",
085          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
086
087  /** Meta attributes removed during a PATCH operation. */
088  public static final AttributeDescriptor META_ATTRIBUTES =
089      AttributeDescriptor.newAttribute("attributes",
090          "attribute", AttributeDescriptor.DataType.STRING,
091          "The names of the attributes to remove from the Resource during a " +
092              "PATCH operation",
093          SCIMConstants.SCHEMA_URI_CORE, true, false, false, false,
094          AttributeDescriptor.createSubAttribute("value",
095            AttributeDescriptor.DataType.STRING,
096            "The attribute's significant value",
097            SCIMConstants.SCHEMA_URI_CORE, false, true, false));
098
099  /** Meta attribute. */
100  public static final AttributeDescriptor META =
101      AttributeDescriptor.createAttribute("meta",
102          AttributeDescriptor.DataType.COMPLEX,
103          "A complex type containing metadata about the resource",
104          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
105          META_CREATED, META_LAST_MODIFIED, META_LOCATION, META_VERSION,
106          META_ATTRIBUTES);
107
108  //// 6.  SCIM User Schema ////
109  //// 6.1.  Singular Attributes ////
110
111  /** Username attribute. */
112  public static final AttributeDescriptor USER_NAME =
113      AttributeDescriptor.createAttribute("userName",
114          AttributeDescriptor.DataType.STRING,
115          "Unique identifier for the User, typically used by the user to " +
116              "directly authenticate to the Service Provider",
117          SCIMConstants.SCHEMA_URI_CORE, false, true, false);
118
119  /** Formatted name attribute. */
120  public static final AttributeDescriptor NAME_FORMATTED =
121      AttributeDescriptor.createSubAttribute("formatted",
122          AttributeDescriptor.DataType.STRING,
123          "The full name, including all middle names, titles, and suffixes " +
124              "as appropriate, formatted for display (e.g. Ms. Barbara Jane " +
125              "Jensen, III.)",
126          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
127
128  /** Family name attribute. */
129  public static final AttributeDescriptor NAME_FAMILY_NAME =
130      AttributeDescriptor.createSubAttribute("familyName",
131          AttributeDescriptor.DataType.STRING,
132          "The family name of the User, or \"Last Name\" in most Western " +
133              "languages (e.g. Jensen given the full name Ms. Barbara Jane " +
134              "Jensen, III.)",
135          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
136
137  /** Given name attribute. */
138  public static final AttributeDescriptor NAME_GIVEN_NAME =
139      AttributeDescriptor.createSubAttribute("givenName",
140          AttributeDescriptor.DataType.STRING,
141          "The given name of the User, or \"First Name\" in most Western " +
142              "languages (e.g. Barbara given the full name Ms. Barbara Jane " +
143              "Jensen, III.)",
144          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
145
146  /** Middle name attribute. */
147  public static final AttributeDescriptor NAME_MIDDLE_NAME =
148      AttributeDescriptor.createSubAttribute("middleName",
149          AttributeDescriptor.DataType.STRING,
150          "The middle name(s) of the User (e.g. Jane given the full name Ms. " +
151              "Barbara Jane Jensen, III.)",
152          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
153
154  /** Honorific name prefix attribute. */
155  public static final AttributeDescriptor NAME_HONORIFIC_PREFIX =
156      AttributeDescriptor.createSubAttribute("honorificPrefix",
157          AttributeDescriptor.DataType.STRING,
158          "The honorific prefix(es) of the User, or \"Title\" in most " +
159              "Western languages (e.g. Ms. given the full name Ms. Barbara " +
160              "Jane Jensen, III.)",
161          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
162
163  /** Honorific name suffix attribute. */
164  public static final AttributeDescriptor NAME_HONORIFIC_SUFFIX =
165      AttributeDescriptor.createSubAttribute("honorificSuffix",
166          AttributeDescriptor.DataType.STRING,
167          "The honorific suffix(es) of the User, or \"Suffix\" in most " +
168              "Western languages (e.g. III. given the full name Ms. Barbara " +
169              "Jane Jensen, III.)",
170          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
171
172  /** Name attribute. */
173  public static final AttributeDescriptor NAME =
174      AttributeDescriptor.createAttribute("name",
175          AttributeDescriptor.DataType.COMPLEX,
176          "The components of the User's real name",
177          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
178          NAME_FORMATTED, NAME_FAMILY_NAME, NAME_GIVEN_NAME, NAME_MIDDLE_NAME,
179          NAME_HONORIFIC_PREFIX, NAME_HONORIFIC_SUFFIX);
180
181  /** Display name attribute. */
182  public static final AttributeDescriptor DISPLAY_NAME =
183      AttributeDescriptor.createAttribute("displayName",
184          AttributeDescriptor.DataType.STRING,
185          "The name of the User, suitable for display to end-users",
186          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
187
188  /** Nick name attribute. */
189  public static final AttributeDescriptor NICK_NAME =
190      AttributeDescriptor.createAttribute("nickName",
191          AttributeDescriptor.DataType.STRING,
192          "The casual way to address the user in real life, e.g. \"Bob\" or " +
193              "\"Bobby\" instead of \"Robert\"",
194          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
195
196  /** Profile URL attribute. */
197  public static final AttributeDescriptor PROFILE_URL =
198      AttributeDescriptor.createAttribute("profileUrl",
199          AttributeDescriptor.DataType.STRING,
200          "URL to a page representing the User's online profile",
201          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
202
203  /** Title attribute. */
204  public static final AttributeDescriptor TITLE =
205      AttributeDescriptor.createAttribute("title",
206          AttributeDescriptor.DataType.STRING,
207          "The User's title, such as \"Vice President\"",
208          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
209
210  /** User type attribute. */
211  public static final AttributeDescriptor USER_TYPE =
212      AttributeDescriptor.createAttribute("userType",
213          AttributeDescriptor.DataType.STRING,
214          "The organization-to-user relationship",
215          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
216
217  /** Preferred language attribute. */
218  public static final AttributeDescriptor PREFERRED_LANGUAGE =
219      AttributeDescriptor.createAttribute("preferredLanguage",
220          AttributeDescriptor.DataType.STRING,
221          "The User's preferred written or spoken language. Generally used " +
222              "for selecting a localized User interface.  Valid values are " +
223              "concatenation of the ISO 639-1 two-letter language code, an " +
224              "underscore, and the ISO 3166-1 two-letter country code; e.g., " +
225              "specifies the language English and country US",
226          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
227
228  /** Locale attribute. */
229  public static final AttributeDescriptor LOCALE =
230      AttributeDescriptor.createAttribute("locale",
231          AttributeDescriptor.DataType.STRING,
232          "Used to indicate the User's default location for purposes of " +
233              "localizing items such as currency, date time format, " +
234              "ISO 639-1 two-letter language code an underscore, and the " +
235              "ISO 3166-1 two-letter country code; e.g., 'en_US' specifies " +
236              "the language English and country US",
237          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
238
239  /** Time zone attribute. */
240  public static final AttributeDescriptor TIMEZONE =
241      AttributeDescriptor.createAttribute("timezone",
242          AttributeDescriptor.DataType.STRING,
243          "The User's time zone in the \"Olson\" timezone database format; " +
244              "e.g.,'America/Los_Angeles'",
245          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
246
247  /** Active status attribute. */
248  public static final AttributeDescriptor ACTIVE =
249      AttributeDescriptor.createAttribute("active",
250          AttributeDescriptor.DataType.BOOLEAN,
251          "A Boolean value indicating the User's administrative status",
252          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
253
254  /** Password attribute. */
255  public static final AttributeDescriptor PASSWORD =
256      AttributeDescriptor.createAttribute("password",
257          AttributeDescriptor.DataType.STRING,
258          "The User's clear text password. This attribute is intended to be " +
259              "used as a means to specify an initial password when creating " +
260              "a new User or to reset an existing User's password. This " +
261              "value will never be returned by a Service Provider in any form",
262          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
263
264  //// 6.2. Multi-valued Attributes ////
265
266  /** Emails attribute. */
267  public static final AttributeDescriptor EMAILS =
268      AttributeDescriptor.createMultiValuedAttribute("emails",
269          "email", "E-mail addresses for the User",
270          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
271          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
272              AttributeDescriptor.DataType.STRING),
273          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE),
274          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
275          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
276              "work", "home", "other"));
277
278  /** Phone numbers attribute. */
279  public static final AttributeDescriptor PHONE_NUMBERS =
280      AttributeDescriptor.createMultiValuedAttribute("phoneNumbers",
281          "phoneNumber", "Phone numbers for the User",
282          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
283          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
284              AttributeDescriptor.DataType.STRING),
285          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE),
286          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
287          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
288              "fax", "pager", "other"));
289
290  /** IMs attribute. */
291  public static final AttributeDescriptor IMS =
292      AttributeDescriptor.createMultiValuedAttribute("ims",
293          "im", "Instant messaging address for the User",
294          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
295          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
296              AttributeDescriptor.DataType.STRING),
297          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE),
298          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
299          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
300              "aim", "gtalk", "icq", "xmpp", "msn", "skype", "qq", "yahoo"));
301
302  /** Photos attribute. */
303  public static final AttributeDescriptor PHOTOS =
304      AttributeDescriptor.createMultiValuedAttribute("photos",
305          "photo", "URL of photos of the User",
306          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
307          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
308              AttributeDescriptor.DataType.STRING),
309          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE),
310          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
311          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
312              "photo", "thumbnail"));
313
314  /** Formatted-address attribute. */
315  public static final AttributeDescriptor ADDRESS_FORMATTED =
316      AttributeDescriptor.createSubAttribute("formatted",
317          AttributeDescriptor.DataType.STRING,
318          "The full mailing address, formatted for display or use with a " +
319              "mailing label",
320          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
321
322  /** Street address attribute. */
323  public static final AttributeDescriptor ADDRESS_STREET_ADDRESS =
324      AttributeDescriptor.createSubAttribute("streetAddress",
325          AttributeDescriptor.DataType.STRING,
326          "The full street address component, which may include house " +
327              "number, street name, P.O. box, and multi-line extended street " +
328              "address information",
329          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
330
331  /** Address locality attribute. */
332  public static final AttributeDescriptor ADDRESS_LOCALITY =
333      AttributeDescriptor.createSubAttribute("locality",
334          AttributeDescriptor.DataType.STRING,
335          "The city or locality component",
336          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
337
338  /** Address region attribute. */
339  public static final AttributeDescriptor ADDRESS_REGION =
340      AttributeDescriptor.createSubAttribute("region",
341          AttributeDescriptor.DataType.STRING,
342          "The state or region component",
343          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
344
345  /** Address postal code attribute. */
346  public static final AttributeDescriptor ADDRESS_POSTAL_CODE =
347      AttributeDescriptor.createSubAttribute("postalCode",
348          AttributeDescriptor.DataType.STRING,
349          "The zipcode or postal code component",
350          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
351
352  /** Address country attribute. */
353  public static final AttributeDescriptor ADDRESS_COUNTRY =
354      AttributeDescriptor.createSubAttribute("country",
355          AttributeDescriptor.DataType.STRING,
356          "The country name component",
357          SCIMConstants.SCHEMA_URI_CORE, false, false, false);
358
359  /** Addresses attribute. */
360  public static final AttributeDescriptor ADDRESSES =
361      AttributeDescriptor.createMultiValuedAttribute("addresses",
362          "address", "A physical mailing address for this User",
363          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
364          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
365          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
366              "work", "home", "other"),
367          ADDRESS_FORMATTED, ADDRESS_STREET_ADDRESS, ADDRESS_LOCALITY,
368          ADDRESS_REGION, ADDRESS_POSTAL_CODE, ADDRESS_COUNTRY);
369
370  /** Groups attribute. */
371  public static final AttributeDescriptor GROUPS =
372      AttributeDescriptor.createMultiValuedAttribute("groups",
373          "group", "A list of groups that the user belongs to",
374          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
375          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
376              AttributeDescriptor.DataType.STRING),
377          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE),
378          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
379              "direct", "indirect"));
380
381  /** Entitlements attribute. */
382  public static final AttributeDescriptor ENTITLEMENTS =
383      AttributeDescriptor.createMultiValuedAttribute("entitlements",
384          "entitlement",
385          "A list of entitlements for the User that represent a thing the " +
386              "User has. That is, an entitlement is an additional right to a " +
387              "thing, object or service",
388          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
389          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
390              AttributeDescriptor.DataType.STRING));
391
392  /** Roles attribute. */
393  public static final AttributeDescriptor ROLES =
394      AttributeDescriptor.createMultiValuedAttribute("roles",
395          "role",
396          "A list of roles for the User that collectively represent who the " +
397              "User is",
398          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
399          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
400              AttributeDescriptor.DataType.STRING));
401
402  /** X.509 certificates attribute. */
403  public static final AttributeDescriptor X509CERTIFICATES =
404      AttributeDescriptor.createMultiValuedAttribute("x509Certificates",
405          "x509Certificate",
406          "A list of certificates issued to the User. Values are DER " +
407              "encoded x509.",
408          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
409          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
410              AttributeDescriptor.DataType.BINARY));
411
412  //// 7.  SCIM Enterprise User Schema Extension ////
413
414  /** Employee number attribute. */
415  public static final AttributeDescriptor EMPLOYEE_NUMBER =
416      AttributeDescriptor.createAttribute("employeeNumber",
417          AttributeDescriptor.DataType.STRING,
418          "Numeric or alphanumeric identifier assigned to a person, " +
419              "typically based on order of hire or association with an " +
420              "organization",
421          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
422          false, false);
423
424  /** Cost center attribute. */
425  public static final AttributeDescriptor COST_CENTER =
426      AttributeDescriptor.createAttribute("costCenter",
427          AttributeDescriptor.DataType.STRING,
428          "Identifies the name of a cost center",
429          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
430          false, false);
431
432  /** Organization attribute. */
433  public static final AttributeDescriptor ORGANIZATION =
434      AttributeDescriptor.createAttribute("organization",
435          AttributeDescriptor.DataType.STRING,
436          "Identifies the name of an organization",
437          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
438          false, false);
439
440  /** Division attribute. */
441  public static final AttributeDescriptor DIVISION =
442      AttributeDescriptor.createAttribute("division",
443          AttributeDescriptor.DataType.STRING,
444          "Identifies the name of a division",
445          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
446          false, false);
447
448  /** Department attribute. */
449  public static final AttributeDescriptor DEPARTMENT =
450      AttributeDescriptor.createAttribute("department",
451          AttributeDescriptor.DataType.STRING,
452          "Identifies the name of a department",
453          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
454          false, false);
455
456  /** Manager ID attribute. */
457  public static final AttributeDescriptor MANAGER_ID =
458      AttributeDescriptor.createSubAttribute("managerId",
459          AttributeDescriptor.DataType.STRING,
460          "The id of the SCIM resource representing the User's manager",
461          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false, true, false);
462
463  /** Manager display name attribute. */
464  public static final AttributeDescriptor MANAGER_DISPLAY_NAME =
465      AttributeDescriptor.createSubAttribute("displayName",
466          AttributeDescriptor.DataType.STRING,
467          "The displayName of the User's manager",
468          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false, false, false);
469
470  /** Manager attribute. */
471  public static final AttributeDescriptor MANAGER =
472      AttributeDescriptor.createAttribute("manager",
473          AttributeDescriptor.DataType.COMPLEX, "The User's manager",
474          SCIMConstants.SCHEMA_URI_ENTERPRISE_EXTENSION, false,
475          false, false, MANAGER_ID, MANAGER_DISPLAY_NAME);
476
477  //// 8.  SCIM Group Schema ////
478
479  /** Group display name attribute. */
480  public static final AttributeDescriptor GROUP_DISPLAY_NAME =
481      AttributeDescriptor.createAttribute("displayName",
482          AttributeDescriptor.DataType.STRING,
483          "A human readable name for the Group",
484          SCIMConstants.SCHEMA_URI_CORE, false, true, false);
485
486  /** Members attribute. */
487  public static final AttributeDescriptor MEMBERS =
488      AttributeDescriptor.createMultiValuedAttribute("members",
489          "member", "A list of members of the Group",
490          SCIMConstants.SCHEMA_URI_CORE, false, false, false,
491          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
492              "User", "Group"),
493          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
494              AttributeDescriptor.DataType.STRING),
495          createMultiValuedDisplayDescriptor(SCIMConstants.SCHEMA_URI_CORE));
496
497  //// 9.  Service Provider Configuration Schema ////
498
499  /** Configuration documentation attribute. */
500  public static final AttributeDescriptor CONFIG_DOCUMENTATION_URL =
501      AttributeDescriptor.createAttribute("documentationUrl",
502          AttributeDescriptor.DataType.STRING,
503          "An HTTP addressable URL pointing to the Service Provider's human " +
504              "consumable help documentation",
505          SCIMConstants.SCHEMA_URI_CORE, true, false, false);
506
507  /** PATCH operation-supported attribute. */
508  public static final AttributeDescriptor PATCH_SUPPORTED =
509      AttributeDescriptor.createSubAttribute("supported",
510          AttributeDescriptor.DataType.BOOLEAN,
511          "Boolean value specifying whether the PATCH operation is supported",
512          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
513
514  /** Bulk processing-supported attribute. */
515  public static final AttributeDescriptor BULK_SUPPORTED =
516      AttributeDescriptor.createSubAttribute("supported",
517          AttributeDescriptor.DataType.BOOLEAN,
518          "Boolean value specifying whether the BULK operation is supported",
519          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
520
521  /** Bulk max operations attribute. */
522  public static final AttributeDescriptor BULK_MAX_OPERATIONS =
523      AttributeDescriptor.createSubAttribute("maxOperations",
524          AttributeDescriptor.DataType.INTEGER,
525          "An integer value specifying the maximum number of resource " +
526              "operations in a BULK operation",
527          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
528
529  /** Bulk max payload size attribute. */
530  public static final AttributeDescriptor BULK_MAX_PAYLOAD_SIZE =
531      AttributeDescriptor.createSubAttribute("maxPayloadSize",
532          AttributeDescriptor.DataType.INTEGER,
533          "An integer value specifying the maximum payload size in bytes " +
534              "of a BULK operation",
535          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
536
537  /** Filter-supported attribute. */
538  public static final AttributeDescriptor FILTER_SUPPORTED =
539      AttributeDescriptor.createSubAttribute("supported",
540          AttributeDescriptor.DataType.BOOLEAN,
541          "Boolean value specifying whether the BULK operation is supported",
542          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
543
544  /** Filter max results attribute. */
545  public static final AttributeDescriptor FILTER_MAX_RESULTS =
546      AttributeDescriptor.createSubAttribute("maxResults",
547          AttributeDescriptor.DataType.INTEGER,
548          "Integer value specifying the maximum number of Resources returned " +
549              "in a response",
550          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
551
552  /** Change password-supported attribute. */
553  public static final AttributeDescriptor CHANGE_PASSWORD_SUPPORTED =
554      AttributeDescriptor.createSubAttribute("supported",
555          AttributeDescriptor.DataType.BOOLEAN,
556          "Boolean value specifying whether the Change Password operation " +
557              "is supported",
558          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
559
560  /** Sorting-supported attribute. */
561  public static final AttributeDescriptor SORT_SUPPORTED =
562      AttributeDescriptor.createSubAttribute("supported",
563          AttributeDescriptor.DataType.BOOLEAN,
564          "Boolean value specifying whether sorting is supported",
565          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
566
567  /** ETag-supported attribute. */
568  public static final AttributeDescriptor ETAG_SUPPORTED =
569      AttributeDescriptor.createSubAttribute("supported",
570          AttributeDescriptor.DataType.BOOLEAN,
571          "Boolean value specifying whether Etag resource versions are " +
572              "supported",
573          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
574
575  /** Authentication scheme name attribute. */
576  public static final AttributeDescriptor AUTH_SCHEME_NAME =
577      AttributeDescriptor.createSubAttribute("name",
578          AttributeDescriptor.DataType.STRING,
579          "The common authentication scheme name.",
580          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
581
582  /** Authentication scheme description attribute. */
583  public static final AttributeDescriptor AUTH_SCHEME_DESCRIPTION =
584      AttributeDescriptor.createSubAttribute("description",
585          AttributeDescriptor.DataType.STRING,
586          "A description of the Authentication Scheme.",
587          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
588
589  /** Authentication scheme specification URL attribute. */
590  public static final AttributeDescriptor AUTH_SCHEME_SPEC_URL =
591      AttributeDescriptor.createSubAttribute("specUrl",
592          AttributeDescriptor.DataType.STRING,
593          "A HTTP addressable URL pointing to the Authentication Scheme's " +
594              "specification.",
595          SCIMConstants.SCHEMA_URI_CORE, true, false, false);
596
597  /** Authentication scheme documentation URL attribute. */
598  public static final AttributeDescriptor AUTH_SCHEME_DOCUMENTATION_URL =
599      AttributeDescriptor.createSubAttribute("documentationUrl",
600          AttributeDescriptor.DataType.STRING,
601          "A HTTP addressable URL pointing to the Authentication Scheme's " +
602              "usage documentation.",
603          SCIMConstants.SCHEMA_URI_CORE, true, false, false);
604
605  /** XML data type-supported attribute. */
606  public static final AttributeDescriptor XML_DATA_TYPE_SUPPORTED =
607      AttributeDescriptor.createSubAttribute("supported",
608          AttributeDescriptor.DataType.BOOLEAN,
609          "Boolean value specifying whether the XML data format is supported",
610          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
611
612  /** PATCH configuration options attribute. */
613  public static final AttributeDescriptor PATCH_CONFIG =
614      AttributeDescriptor.createAttribute("patch",
615          AttributeDescriptor.DataType.COMPLEX,
616          "A complex type that specifies PATCH configuration options",
617          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
618          PATCH_SUPPORTED);
619
620  /** Bulk operations configuration attribute. */
621  public static final AttributeDescriptor BULK_CONFIG =
622      AttributeDescriptor.createAttribute("bulk",
623          AttributeDescriptor.DataType.COMPLEX,
624          "A complex type that specifies BULK configuration options",
625          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
626          BULK_SUPPORTED, BULK_MAX_OPERATIONS, BULK_MAX_PAYLOAD_SIZE);
627
628  /** Filter configuration attribute. */
629  public static final AttributeDescriptor FILTER_CONFIG =
630      AttributeDescriptor.createAttribute("filter",
631          AttributeDescriptor.DataType.COMPLEX,
632          "A complex type that specifies Filter configuration options",
633          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
634          FILTER_SUPPORTED, FILTER_MAX_RESULTS);
635
636  /** Change password configuration attribute. */
637  public static final AttributeDescriptor CHANGE_PASSWORD_CONFIG =
638      AttributeDescriptor.createAttribute("changePassword",
639          AttributeDescriptor.DataType.COMPLEX,
640          "A complex type that specifies Change Password configuration options",
641          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
642          CHANGE_PASSWORD_SUPPORTED);
643
644  /** Sorting configuration attribute. */
645  public static final AttributeDescriptor SORT_CONFIG =
646      AttributeDescriptor.createAttribute("sort",
647          AttributeDescriptor.DataType.COMPLEX,
648          "A complex type that specifies Sort configuration options",
649          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
650          SORT_SUPPORTED);
651
652  /** ETag configuration attribute. */
653  public static final AttributeDescriptor ETAG_CONFIG =
654      AttributeDescriptor.createAttribute("etag",
655          AttributeDescriptor.DataType.COMPLEX,
656          "A complex type that specifies Etag configuration options",
657          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
658          ETAG_SUPPORTED);
659
660  /** Authentication schemes attribute. */
661  public static final AttributeDescriptor AUTH_SCHEMES =
662      AttributeDescriptor.createMultiValuedAttribute("authenticationSchemes",
663          "authenticationScheme",
664          "A complex type that specifies supported Authentication Scheme " +
665              "properties.",
666          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
667          createMultiValuedTypeDescriptor(SCIMConstants.SCHEMA_URI_CORE,
668              "OAuth", "OAuth2", "HttpBasic", "httpDigest"),
669          createMultiValuedPrimaryDescriptor(SCIMConstants.SCHEMA_URI_CORE),
670          AUTH_SCHEME_NAME, AUTH_SCHEME_DESCRIPTION, AUTH_SCHEME_SPEC_URL,
671          AUTH_SCHEME_DOCUMENTATION_URL);
672
673  /** XML data type configuration attribute. */
674  public static final AttributeDescriptor XML_DATA_TYPE_CONFIG =
675      AttributeDescriptor.createAttribute(
676          "xmlDataFormat",
677          AttributeDescriptor.DataType.COMPLEX,
678          "A complex type that specifies whether the XML data format is " +
679          "supported",
680          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
681          XML_DATA_TYPE_SUPPORTED);
682
683  //// 10.  Resource Schema ////
684
685  /** Resource name attribute. */
686  public static final AttributeDescriptor RESOURCE_NAME =
687      AttributeDescriptor.createAttribute("name",
688          AttributeDescriptor.DataType.STRING,
689          "The addressable Resource endpoint name",
690          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
691
692  /** Resource description attribute. */
693  public static final AttributeDescriptor RESOURCE_DESCRIPTION =
694      AttributeDescriptor.createAttribute("description",
695          AttributeDescriptor.DataType.STRING,
696          "The Resource's human readable description",
697          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
698
699  /** Resource schema. */
700  public static final AttributeDescriptor RESOURCE_SCHEMA =
701      AttributeDescriptor.createAttribute("schema",
702          AttributeDescriptor.DataType.STRING,
703          "The Resource's associated schema URN",
704          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
705
706  /** Resource endpoint. */
707  public static final AttributeDescriptor RESOURCE_ENDPOINT =
708      AttributeDescriptor.createAttribute("endpoint",
709          AttributeDescriptor.DataType.STRING,
710          "The Resource's HTTP addressable query endpoint relative to the " +
711              "Base URL",
712          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
713
714  /** Attribute name. */
715  public static final AttributeDescriptor ATTRIBUTES_NAME =
716      AttributeDescriptor.createSubAttribute("name",
717          AttributeDescriptor.DataType.STRING,
718          "The attribute's name", SCIMConstants.SCHEMA_URI_CORE,
719          true, true, false);
720
721  /** Attribute type. */
722  public static final AttributeDescriptor ATTRIBUTES_TYPE =
723      AttributeDescriptor.createSubAttribute("type",
724          AttributeDescriptor.DataType.STRING,
725          "The attribute's data type", SCIMConstants.SCHEMA_URI_CORE,
726          true, true, false);
727
728  /** Multivalued type. */
729  public static final AttributeDescriptor ATTRIBUTES_MULTIVALUED =
730      AttributeDescriptor.createSubAttribute("multiValued",
731          AttributeDescriptor.DataType.BOOLEAN,
732          "Boolean value indicating the attribute's plurality",
733          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
734
735  /** Multivalued child name. */
736  public static final AttributeDescriptor ATTRIBUTES_MULTIVALUED_CHILD_NAME =
737      AttributeDescriptor.createSubAttribute("multiValuedAttributeChildName",
738          AttributeDescriptor.DataType.STRING,
739          "String value specifying the child XML element name; e.g., the " +
740              "'emails' attribute value is 'email', 'phoneNumbers' is " +
741              "'phoneNumber'.",
742          SCIMConstants.SCHEMA_URI_CORE, true, false, false);
743
744  /** Attribute description. */
745  public static final AttributeDescriptor ATTRIBUTES_DESCRIPTION =
746      AttributeDescriptor.createSubAttribute("description",
747          AttributeDescriptor.DataType.STRING,
748          "The attribute's human readable description",
749          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
750
751  /** Attribute schema. */
752  public static final AttributeDescriptor ATTRIBUTES_SCHEMA =
753      AttributeDescriptor.createSubAttribute("schema",
754          AttributeDescriptor.DataType.STRING,
755          "The attribute's associated schema", SCIMConstants.SCHEMA_URI_CORE,
756          true, true, false);
757
758  /** Attribute read-only. */
759  public static final AttributeDescriptor ATTRIBUTES_READ_ONLY =
760      AttributeDescriptor.createSubAttribute("readOnly",
761          AttributeDescriptor.DataType.BOOLEAN,
762          "A Boolean value that specifies if the attribute is mutable",
763          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
764
765  /** Attribute required. */
766  public static final AttributeDescriptor ATTRIBUTES_REQUIRED =
767      AttributeDescriptor.createSubAttribute("required",
768          AttributeDescriptor.DataType.BOOLEAN,
769          "A Boolean value that specifies if the attribute is required",
770          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
771
772  /** Attribute case-exact. */
773  public static final AttributeDescriptor ATTRIBUTES_CASE_EXACT =
774      AttributeDescriptor.createSubAttribute("caseExact",
775          AttributeDescriptor.DataType.BOOLEAN,
776          "A Boolean value that specifies if the string attribute is case " +
777              "sensitive",
778          SCIMConstants.SCHEMA_URI_CORE, true, true, false);
779
780  /** Attribute canonical values. */
781  public static final AttributeDescriptor ATTRIBUTES_CANONICAL_VALUES =
782      AttributeDescriptor.createMultiValuedAttribute("canonicalValues",
783          "canonicalValue", "A collection of canonical values",
784          SCIMConstants.SCHEMA_URI_CORE, true, false, false,
785          createMultiValuedValueDescriptor(SCIMConstants.SCHEMA_URI_CORE,
786              AttributeDescriptor.DataType.STRING));
787
788  /** Resource sub-attributes. */
789  public static final AttributeDescriptor RESOURCE_SUB_ATTRIBUTES =
790      AttributeDescriptor.newAttribute("subAttributes",
791          "subAttribute", AttributeDescriptor.DataType.COMPLEX,
792          "A list specifying the contained attributes",
793          SCIMConstants.SCHEMA_URI_CORE, true, true, false,
794          false, ATTRIBUTES_NAME, ATTRIBUTES_TYPE, ATTRIBUTES_MULTIVALUED,
795          ATTRIBUTES_MULTIVALUED_CHILD_NAME, ATTRIBUTES_DESCRIPTION,
796          ATTRIBUTES_READ_ONLY, ATTRIBUTES_REQUIRED, ATTRIBUTES_CASE_EXACT,
797          ATTRIBUTES_CANONICAL_VALUES);
798
799  /** Resource attributes. */
800  public static final AttributeDescriptor RESOURCE_ATTRIBUTES =
801      AttributeDescriptor.newAttribute("attributes",
802          "attribute", AttributeDescriptor.DataType.COMPLEX,
803          "A complex type that specifies the set of associated " +
804              "Resource attributes", SCIMConstants.SCHEMA_URI_CORE,
805          true, true, true, false, ATTRIBUTES_NAME, ATTRIBUTES_TYPE,
806          ATTRIBUTES_MULTIVALUED, ATTRIBUTES_MULTIVALUED_CHILD_NAME,
807          ATTRIBUTES_DESCRIPTION, ATTRIBUTES_SCHEMA,
808          ATTRIBUTES_READ_ONLY, ATTRIBUTES_REQUIRED, ATTRIBUTES_CASE_EXACT,
809          RESOURCE_SUB_ATTRIBUTES);
810
811  /** Nesting attributes resolver. */
812  public static final AttributeDescriptor.AttributeDescriptorResolver
813        NESTING_ATTRIBUTES_RESOLVER =
814        new AttributeDescriptor.AttributeDescriptorResolver(true);
815
816  /**
817   * The SCIM Resource Schema.
818   */
819  public static final ResourceDescriptor RESOURCE_SCHEMA_DESCRIPTOR;
820
821  static
822  {
823    SCIMObject scimObject = new SCIMObject();
824    scimObject.setAttribute(SCIMAttribute.create(
825        RESOURCE_NAME, SCIMAttributeValue.createStringValue(
826        SCIMConstants.RESOURCE_NAME_SCHEMA)));
827    scimObject.setAttribute(SCIMAttribute.create(
828        RESOURCE_DESCRIPTION, SCIMAttributeValue.createStringValue(
829        "The Resource schema specifies the Attribute(s) and meta-data that " +
830            "constitute a Resource")));
831    scimObject.setAttribute(SCIMAttribute.create(
832        RESOURCE_SCHEMA, SCIMAttributeValue.createStringValue(
833        SCIMConstants.SCHEMA_URI_CORE)));
834    scimObject.setAttribute(SCIMAttribute.create(
835        RESOURCE_ENDPOINT, SCIMAttributeValue.createStringValue(
836        SCIMConstants.RESOURCE_ENDPOINT_SCHEMAS)));
837
838    SCIMAttributeValue[] entries = new SCIMAttributeValue[8];
839
840    try
841    {
842      entries[0] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
843          fromInstance(RESOURCE_ATTRIBUTES, ID);
844      entries[1] = NESTING_ATTRIBUTES_RESOLVER.
845          fromInstance(RESOURCE_ATTRIBUTES, META);
846      entries[2] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
847          fromInstance(RESOURCE_ATTRIBUTES, EXTERNAL_ID);
848      entries[3] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
849          fromInstance(RESOURCE_ATTRIBUTES, RESOURCE_NAME);
850      entries[4] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
851          fromInstance(RESOURCE_ATTRIBUTES, RESOURCE_DESCRIPTION);
852      entries[5] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
853          fromInstance(RESOURCE_ATTRIBUTES, RESOURCE_SCHEMA);
854      entries[6] = AttributeDescriptor.ATTRIBUTE_DESCRIPTOR_RESOLVER.
855          fromInstance(RESOURCE_ATTRIBUTES, RESOURCE_ENDPOINT);
856      entries[7] = NESTING_ATTRIBUTES_RESOLVER.
857          fromInstance(RESOURCE_ATTRIBUTES, RESOURCE_ATTRIBUTES);
858    }
859    catch(InvalidResourceException e)
860    {
861      // This should not occur as these are all defined here...
862      throw new RuntimeException(e);
863    }
864
865    scimObject.setAttribute(
866        SCIMAttribute.create(RESOURCE_ATTRIBUTES, entries));
867
868
869    RESOURCE_SCHEMA_DESCRIPTOR = new ResourceDescriptor(null, scimObject)
870    {
871      @Override
872      public ResourceDescriptor getResourceDescriptor() {
873        return this;
874      }
875
876      @Override
877      public Collection<AttributeDescriptor> getAttributes() {
878        return getAttributeValues(SCIMConstants.SCHEMA_URI_CORE,
879            "attributes", NESTING_ATTRIBUTES_RESOLVER);
880      }
881    };
882  }
883
884  /**
885   * The SCIM Service Provider Configuration Schema.
886   */
887  public static final ResourceDescriptor
888      SERVICE_PROVIDER_CONFIG_SCHEMA_DESCRIPTOR =
889      ResourceDescriptor.create(
890          SCIMConstants.RESOURCE_NAME_SERVICE_PROVIDER_CONFIG,
891          "The Service Provider Configuration Resource enables a Service " +
892          "Provider to expose its compliance with the SCIM specification in " +
893          "a standardized form as well as provide additional implementation " +
894          "details to Consumers",
895          SCIMConstants.SCHEMA_URI_CORE,
896          SCIMConstants.RESOURCE_ENDPOINT_SERVICE_PROVIDER_CONFIG,
897          ID, META, CONFIG_DOCUMENTATION_URL, PATCH_CONFIG, BULK_CONFIG,
898          FILTER_CONFIG, CHANGE_PASSWORD_CONFIG, SORT_CONFIG, ETAG_CONFIG,
899          AUTH_SCHEMES, XML_DATA_TYPE_CONFIG);
900
901  /**
902   * The SCIM User Schema.
903   */
904  public static final ResourceDescriptor USER_DESCRIPTOR =
905    createCustomUserResourceDescriptor(SCIMConstants.RESOURCE_NAME_USER,
906        SCIMConstants.RESOURCE_ENDPOINT_USERS);
907
908  /**
909   * Creates a custom SCIM User Schema resource descriptor.
910   *
911   * @param userResourceName   Provide a custom user resource name.
912   * @param usersEndpointName  Provide a custom users endpoint name.
913   * @return User ResourceDescriptor
914   */
915  public static ResourceDescriptor createCustomUserResourceDescriptor(
916    final String userResourceName, final String usersEndpointName)
917  {
918    return ResourceDescriptor.create(userResourceName,
919      "SCIM core resource for representing users",
920      SCIMConstants.SCHEMA_URI_CORE, usersEndpointName,
921      ID, META, EXTERNAL_ID, USER_NAME, NAME, DISPLAY_NAME, NICK_NAME,
922      PROFILE_URL, TITLE, USER_TYPE, PREFERRED_LANGUAGE, LOCALE, TIMEZONE,
923      ACTIVE, PASSWORD, EMAILS, PHONE_NUMBERS, IMS, PHOTOS, ADDRESSES,
924      GROUPS, ENTITLEMENTS, ROLES, X509CERTIFICATES, EMPLOYEE_NUMBER,
925      COST_CENTER, ORGANIZATION, DIVISION, DEPARTMENT, MANAGER);
926  }
927
928  /**
929   * The SCIM Group Schema.
930   */
931  public static final ResourceDescriptor GROUP_DESCRIPTOR =
932      createCustomGroupResourceDescriptor(SCIMConstants.RESOURCE_NAME_GROUP,
933          SCIMConstants.RESOURCE_ENDPOINT_GROUPS);
934
935  /**
936   * Creates a custom SCIM Group Schema resource descriptor.
937   *
938   * @param groupResourceName   Provide a custom group resource name.
939   * @param groupsEndpointName  Provide a custom groups endpoint name.
940   * @return Group ResourceDescriptor
941   */
942  public static ResourceDescriptor createCustomGroupResourceDescriptor(
943    final String groupResourceName, final String groupsEndpointName)
944  {
945    return ResourceDescriptor.create(groupResourceName,
946      "SCIM core resource for representing groups",
947      SCIMConstants.SCHEMA_URI_CORE, groupsEndpointName,
948      ID, META, EXTERNAL_ID, GROUP_DISPLAY_NAME, MEMBERS);
949  }
950
951  /**
952   * The SCIM AttributeDescriptor for the meta attribute.
953   */
954  public static final AttributeDescriptor META_DESCRIPTOR = META;
955
956  /**
957   * The SCIM AttributeDescriptor for the id attribute.
958   */
959  public static final AttributeDescriptor ID_DESCRIPTOR = ID;
960
961  /**
962   * The SCIM AttributeDescriptor for the externalId attribute.
963   */
964  public static final AttributeDescriptor EXTERNAL_ID_DESCRIPTOR = EXTERNAL_ID;
965
966  //// 3.2 Multi-valued Attributes ////
967  /**
968   * Convenience method to create an attribute descriptor for the type normative
969   * sub-attribute of multi-valued attributes.
970   *
971   * @param schema The attribute's associated schema.
972   * @param canonicalValues The canonical values to include in the descriptor.
973   *
974   * @return The attribute descriptor for the type normative sub-attribute of
975   * multi-valued attributes.
976   */
977  public static AttributeDescriptor createMultiValuedTypeDescriptor(
978      final String schema, final String... canonicalValues)
979  {
980    return  AttributeDescriptor.createSubAttribute("type",
981        AttributeDescriptor.DataType.STRING,
982        "A label indicating the attribute's function; " +
983            "e.g., \"work\" or " + "\"home\"",
984        schema, false, false, false, canonicalValues);
985  }
986
987  /**
988   * Convenience method to create an attribute descriptor for the primary
989   * normative sub-attribute of multi-valued attributes.
990   *
991   * @param schema The attribute's associated schema.
992   *
993   * @return The attribute descriptor for the primary normative sub-attribute of
994   * multi-valued attributes.
995   */
996  public static AttributeDescriptor createMultiValuedPrimaryDescriptor(
997      final String schema)
998  {
999    return AttributeDescriptor.createSubAttribute("primary",
1000        AttributeDescriptor.DataType.BOOLEAN,
1001        "A Boolean value indicating the 'primary' or preferred attribute " +
1002            "value for this attribute",
1003        schema, false, false, false);
1004  }
1005
1006  /**
1007   * Convenience method to create an attribute descriptor for the display
1008   * normative sub-attribute of multi-valued attributes.
1009   *
1010   * @param schema The attribute's associated schema.
1011   *
1012   * @return The attribute descriptor for the display normative sub-attribute of
1013   * multi-valued attributes.
1014   */
1015  public static AttributeDescriptor createMultiValuedDisplayDescriptor(
1016      final String schema)
1017  {
1018    return AttributeDescriptor.createSubAttribute("display",
1019        AttributeDescriptor.DataType.STRING,
1020        "A human readable name, primarily used for display purposes",
1021        schema, true, false, false);
1022  }
1023
1024  /**
1025   * Convenience method to create an attribute descriptor for the operation
1026   * normative sub-attribute of multi-valued attributes.
1027   *
1028   * @param schema The attribute's associated schema.
1029   *
1030   * @return The attribute descriptor for the display operation sub-attribute of
1031   * multi-valued attributes.
1032   */
1033  public static AttributeDescriptor createMultiValuedOperationDescriptor(
1034      final String schema)
1035  {
1036    return AttributeDescriptor.createSubAttribute("operation",
1037        AttributeDescriptor.DataType.STRING,
1038        "The operation to perform on the multi-valued attribute during a " +
1039            "PATCH request",
1040        schema, false, false, false);
1041  }
1042
1043  /**
1044   * Convenience method to create an attribute descriptor for the value
1045   * normative sub-attribute of multi-valued attributes.
1046   *
1047   * @param schema The attribute's associated schema.
1048   * @param dataType The data type of the value sub-attribute.
1049   *
1050   * @return The attribute descriptor for the value normative sub-attribute of
1051   * multi-valued attributes.
1052   */
1053  public static AttributeDescriptor createMultiValuedValueDescriptor(
1054      final String schema, final AttributeDescriptor.DataType dataType)
1055  {
1056    return AttributeDescriptor.createSubAttribute("value", dataType,
1057        "The attribute's significant value", schema, false, true, false);
1058  }
1059
1060
1061  /**
1062   * Add any missing core schema attributes described in section 5.1.
1063   *
1064   * @param attributes The currently defined attributes.
1065   *
1066   * @return The attributes with any missing core schema attributes added.
1067   */
1068  static Collection<AttributeDescriptor> addCommonAttributes(
1069      final Collection<AttributeDescriptor> attributes)
1070  {
1071    boolean idMissing = true;
1072    boolean externalIdMissing = true;
1073    boolean metaMissing = true;
1074    for(AttributeDescriptor attribute : attributes)
1075    {
1076      if(attribute.equals(ID))
1077      {
1078        idMissing = false;
1079      }
1080      if(attribute.equals(EXTERNAL_ID))
1081      {
1082        externalIdMissing = false;
1083      }
1084      if(attribute.equals(META))
1085      {
1086        metaMissing = false;
1087      }
1088    }
1089
1090    if(!idMissing && !externalIdMissing && !metaMissing)
1091    {
1092      return attributes;
1093    }
1094
1095    ArrayList<AttributeDescriptor> missingAttributes =
1096        new ArrayList<AttributeDescriptor>(attributes.size() + 3);
1097    if(idMissing)
1098    {
1099      missingAttributes.add(ID);
1100    }
1101    if(externalIdMissing)
1102    {
1103      missingAttributes.add(EXTERNAL_ID);
1104    }
1105    if(metaMissing)
1106    {
1107      missingAttributes.add(META);
1108    }
1109    missingAttributes.addAll(attributes);
1110    return missingAttributes;
1111  }
1112
1113  /**
1114   * Add any missing core schema sub-attributes described in section 5.1
1115   * and 3.2.
1116   *
1117   * @param attributeDescriptor The attribute descriptor.
1118   * @param subAttributes The map of sub-attributes currently defined.
1119   *
1120   * @return The map of sub-attributes with any missing normative sub-attributes
1121   * added or {@code null} if there are no sub-attributes defined.
1122   */
1123  static Map<String, AttributeDescriptor> addNormativeSubAttributes(
1124      final AttributeDescriptor attributeDescriptor,
1125      final Map<String, AttributeDescriptor> subAttributes)
1126  {
1127    Map<String, AttributeDescriptor> missingSubAttributes =
1128        new LinkedHashMap<String, AttributeDescriptor>();
1129    if(attributeDescriptor.equals(META))
1130    {
1131      if(subAttributes == null ||
1132          !subAttributes.containsKey(META_CREATED.getName()))
1133      {
1134        missingSubAttributes.put(META_CREATED.getName(), META_CREATED);
1135      }
1136      if(subAttributes == null ||
1137          !subAttributes.containsKey(toLowerCase(META_LAST_MODIFIED.getName())))
1138      {
1139        missingSubAttributes.put(toLowerCase(META_LAST_MODIFIED.getName()),
1140            META_LAST_MODIFIED);
1141      }
1142      if(subAttributes == null ||
1143          !subAttributes.containsKey(META_LOCATION.getName()))
1144      {
1145        missingSubAttributes.put(META_LOCATION.getName(), META_LOCATION);
1146      }
1147      if(subAttributes == null ||
1148          !subAttributes.containsKey(META_VERSION.getName()))
1149      {
1150        missingSubAttributes.put(META_VERSION.getName(), META_VERSION);
1151      }
1152      if(subAttributes == null ||
1153          !subAttributes.containsKey(META_ATTRIBUTES.getName()))
1154      {
1155        missingSubAttributes.put(META_ATTRIBUTES.getName(), META_ATTRIBUTES);
1156      }
1157    }
1158    else if(attributeDescriptor.isMultiValued())
1159    {
1160      if(subAttributes == null ||
1161          !subAttributes.containsKey("type"))
1162      {
1163        missingSubAttributes.put("type", createMultiValuedTypeDescriptor(
1164            attributeDescriptor.getSchema()));
1165      }
1166      if(subAttributes == null ||
1167          !subAttributes.containsKey("primary"))
1168      {
1169        missingSubAttributes.put("primary", createMultiValuedPrimaryDescriptor(
1170            attributeDescriptor.getSchema()));
1171      }
1172      if(subAttributes == null ||
1173          !subAttributes.containsKey("display"))
1174      {
1175        missingSubAttributes.put("display", createMultiValuedDisplayDescriptor(
1176            attributeDescriptor.getSchema()));
1177      }
1178      if(subAttributes == null ||
1179          !subAttributes.containsKey("operation"))
1180      {
1181        missingSubAttributes.put("operation",
1182            createMultiValuedOperationDescriptor(
1183                attributeDescriptor.getSchema()));
1184      }
1185      if(attributeDescriptor.getDataType() !=
1186                        AttributeDescriptor.DataType.COMPLEX &&
1187          (subAttributes == null ||
1188              !subAttributes.containsKey("value")))
1189      {
1190        missingSubAttributes.put("value", createMultiValuedValueDescriptor(
1191            attributeDescriptor.getSchema(),
1192            attributeDescriptor.getDataType()));
1193      }
1194    }
1195
1196    if(missingSubAttributes.isEmpty())
1197    {
1198      return subAttributes;
1199    }
1200    if(subAttributes != null)
1201    {
1202      missingSubAttributes.putAll(subAttributes);
1203    }
1204    return missingSubAttributes;
1205  }
1206}