001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.ldap.sdk.schema;
022
023
024
025 import java.io.File;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.io.Serializable;
029 import java.util.ArrayList;
030 import java.util.Arrays;
031 import java.util.Collections;
032 import java.util.LinkedHashMap;
033 import java.util.LinkedHashSet;
034 import java.util.List;
035 import java.util.Map;
036 import java.util.Set;
037 import java.util.concurrent.atomic.AtomicReference;
038
039 import com.unboundid.ldap.sdk.Attribute;
040 import com.unboundid.ldap.sdk.Entry;
041 import com.unboundid.ldap.sdk.Filter;
042 import com.unboundid.ldap.sdk.LDAPConnection;
043 import com.unboundid.ldap.sdk.LDAPException;
044 import com.unboundid.ldap.sdk.ReadOnlyEntry;
045 import com.unboundid.ldap.sdk.ResultCode;
046 import com.unboundid.ldap.sdk.SearchScope;
047 import com.unboundid.ldif.LDIFException;
048 import com.unboundid.ldif.LDIFReader;
049 import com.unboundid.util.NotMutable;
050 import com.unboundid.util.ThreadSafety;
051 import com.unboundid.util.ThreadSafetyLevel;
052
053 import static com.unboundid.ldap.sdk.schema.SchemaMessages.*;
054 import static com.unboundid.util.Debug.*;
055 import static com.unboundid.util.StaticUtils.*;
056 import static com.unboundid.util.Validator.*;
057
058
059
060 /**
061 * This class provides a data structure for representing a directory server
062 * subschema subentry. This includes information about the attribute syntaxes,
063 * matching rules, attribute types, object classes, name forms, DIT content
064 * rules, DIT structure rules, and matching rule uses defined in the server
065 * schema.
066 */
067 @NotMutable()
068 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
069 public final class Schema
070 implements Serializable
071 {
072 /**
073 * The name of the attribute used to hold the attribute syntax definitions.
074 */
075 public static final String ATTR_ATTRIBUTE_SYNTAX = "ldapSyntaxes";
076
077
078
079 /**
080 * The name of the attribute used to hold the attribute type definitions.
081 */
082 public static final String ATTR_ATTRIBUTE_TYPE = "attributeTypes";
083
084
085
086 /**
087 * The name of the attribute used to hold the DIT content rule definitions.
088 */
089 public static final String ATTR_DIT_CONTENT_RULE = "dITContentRules";
090
091
092
093 /**
094 * The name of the attribute used to hold the DIT structure rule definitions.
095 */
096 public static final String ATTR_DIT_STRUCTURE_RULE = "dITStructureRules";
097
098
099
100 /**
101 * The name of the attribute used to hold the matching rule definitions.
102 */
103 public static final String ATTR_MATCHING_RULE = "matchingRules";
104
105
106
107 /**
108 * The name of the attribute used to hold the matching rule use definitions.
109 */
110 public static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse";
111
112
113
114 /**
115 * The name of the attribute used to hold the name form definitions.
116 */
117 public static final String ATTR_NAME_FORM = "nameForms";
118
119
120
121 /**
122 * The name of the attribute used to hold the object class definitions.
123 */
124 public static final String ATTR_OBJECT_CLASS = "objectClasses";
125
126
127
128 /**
129 * The name of the attribute used to hold the DN of the subschema subentry
130 * with the schema information that governs a specified entry.
131 */
132 public static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
133
134
135
136 /**
137 * The default standard schema available for use in the LDAP SDK.
138 */
139 private static final AtomicReference<Schema> DEFAULT_STANDARD_SCHEMA =
140 new AtomicReference<Schema>();
141
142
143
144 /**
145 * The set of request attributes that will be used when retrieving the server
146 * subschema subentry in order to retrieve all of the schema elements.
147 */
148 private static final String[] SCHEMA_REQUEST_ATTRS =
149 {
150 "*",
151 ATTR_ATTRIBUTE_SYNTAX,
152 ATTR_ATTRIBUTE_TYPE,
153 ATTR_DIT_CONTENT_RULE,
154 ATTR_DIT_STRUCTURE_RULE,
155 ATTR_MATCHING_RULE,
156 ATTR_MATCHING_RULE_USE,
157 ATTR_NAME_FORM,
158 ATTR_OBJECT_CLASS
159 };
160
161
162
163 /**
164 * The set of request attributes that will be used when retrieving the
165 * subschema subentry attribute from a specified entry in order to determine
166 * the location of the server schema definitions.
167 */
168 private static final String[] SUBSCHEMA_SUBENTRY_REQUEST_ATTRS =
169 {
170 ATTR_SUBSCHEMA_SUBENTRY
171 };
172
173
174
175 /**
176 * Retrieves the resource path that may be used to obtain a file with a number
177 * of standard schema definitions.
178 */
179 private static final String DEFAULT_SCHEMA_RESOURCE_PATH =
180 "com/unboundid/ldap/sdk/schema/standard-schema.ldif";
181
182
183
184 /**
185 * The serial version UID for this serializable class.
186 */
187 private static final long serialVersionUID = 8081839633831517925L;
188
189
190
191 // A map of all subordinate attribute type definitions for each attribute
192 // type definition.
193 private final Map<AttributeTypeDefinition,List<AttributeTypeDefinition>>
194 subordinateAttributeTypes;
195
196 // The set of attribute syntaxes mapped from lowercase name/OID to syntax.
197 private final Map<String,AttributeSyntaxDefinition> asMap;
198
199 // The set of attribute types mapped from lowercase name/OID to type.
200 private final Map<String,AttributeTypeDefinition> atMap;
201
202 // The set of DIT content rules mapped from lowercase name/OID to rule.
203 private final Map<String,DITContentRuleDefinition> dcrMap;
204
205 // The set of DIT structure rules mapped from rule ID to rule.
206 private final Map<Integer,DITStructureRuleDefinition> dsrMapByID;
207
208 // The set of DIT structure rules mapped from lowercase name to rule.
209 private final Map<String,DITStructureRuleDefinition> dsrMapByName;
210
211 // The set of DIT structure rules mapped from lowercase name to rule.
212 private final Map<String,DITStructureRuleDefinition> dsrMapByNameForm;
213
214 // The set of matching rules mapped from lowercase name/OID to rule.
215 private final Map<String,MatchingRuleDefinition> mrMap;
216
217 // The set of matching rule uses mapped from matching rule OID to use.
218 private final Map<String,MatchingRuleUseDefinition> mruMap;
219
220 // The set of name forms mapped from lowercase name/OID to name form.
221 private final Map<String,NameFormDefinition> nfMapByName;
222
223 // The set of name forms mapped from structural class OID to name form.
224 private final Map<String,NameFormDefinition> nfMapByOC;
225
226 // The set of object classes mapped from lowercase name/OID to class.
227 private final Map<String,ObjectClassDefinition> ocMap;
228
229 // The entry used to create this schema object.
230 private final ReadOnlyEntry schemaEntry;
231
232 // The set of attribute syntaxes defined in the schema.
233 private final Set<AttributeSyntaxDefinition> asSet;
234
235 // The set of attribute types defined in the schema.
236 private final Set<AttributeTypeDefinition> atSet;
237
238 // The set of operational attribute types defined in the schema.
239 private final Set<AttributeTypeDefinition> operationalATSet;
240
241 // The set of user attribute types defined in the schema.
242 private final Set<AttributeTypeDefinition> userATSet;
243
244 // The set of DIT content rules defined in the schema.
245 private final Set<DITContentRuleDefinition> dcrSet;
246
247 // The set of DIT structure rules defined in the schema.
248 private final Set<DITStructureRuleDefinition> dsrSet;
249
250 // The set of matching rules defined in the schema.
251 private final Set<MatchingRuleDefinition> mrSet;
252
253 // The set of matching rule uses defined in the schema.
254 private final Set<MatchingRuleUseDefinition> mruSet;
255
256 // The set of name forms defined in the schema.
257 private final Set<NameFormDefinition> nfSet;
258
259 // The set of object classes defined in the schema.
260 private final Set<ObjectClassDefinition> ocSet;
261
262 // The set of abstract object classes defined in the schema.
263 private final Set<ObjectClassDefinition> abstractOCSet;
264
265 // The set of auxiliary object classes defined in the schema.
266 private final Set<ObjectClassDefinition> auxiliaryOCSet;
267
268 // The set of structural object classes defined in the schema.
269 private final Set<ObjectClassDefinition> structuralOCSet;
270
271
272
273 /**
274 * Creates a new schema object by decoding the information in the provided
275 * entry.
276 *
277 * @param schemaEntry The schema entry to decode.
278 */
279 public Schema(final Entry schemaEntry)
280 {
281 this.schemaEntry = new ReadOnlyEntry(schemaEntry);
282
283 // Decode the attribute syntaxes from the schema entry.
284 String[] defs = schemaEntry.getAttributeValues(ATTR_ATTRIBUTE_SYNTAX);
285 if (defs == null)
286 {
287 asMap = Collections.emptyMap();
288 asSet = Collections.emptySet();
289 }
290 else
291 {
292 final LinkedHashMap<String,AttributeSyntaxDefinition> m =
293 new LinkedHashMap<String,AttributeSyntaxDefinition>(defs.length);
294 final LinkedHashSet<AttributeSyntaxDefinition> s =
295 new LinkedHashSet<AttributeSyntaxDefinition>(defs.length);
296
297 for (final String def : defs)
298 {
299 try
300 {
301 final AttributeSyntaxDefinition as =
302 new AttributeSyntaxDefinition(def);
303 s.add(as);
304 m.put(toLowerCase(as.getOID()), as);
305 }
306 catch (final LDAPException le)
307 {
308 debugException(le);
309 }
310 }
311
312 asMap = Collections.unmodifiableMap(m);
313 asSet = Collections.unmodifiableSet(s);
314 }
315
316
317 // Decode the attribute types from the schema entry.
318 defs = schemaEntry.getAttributeValues(ATTR_ATTRIBUTE_TYPE);
319 if (defs == null)
320 {
321 atMap = Collections.emptyMap();
322 atSet = Collections.emptySet();
323 operationalATSet = Collections.emptySet();
324 userATSet = Collections.emptySet();
325 }
326 else
327 {
328 final LinkedHashMap<String,AttributeTypeDefinition> m =
329 new LinkedHashMap<String,AttributeTypeDefinition>(2*defs.length);
330 final LinkedHashSet<AttributeTypeDefinition> s =
331 new LinkedHashSet<AttributeTypeDefinition>(defs.length);
332 final LinkedHashSet<AttributeTypeDefinition> sUser =
333 new LinkedHashSet<AttributeTypeDefinition>(defs.length);
334 final LinkedHashSet<AttributeTypeDefinition> sOperational =
335 new LinkedHashSet<AttributeTypeDefinition>(defs.length);
336
337 for (final String def : defs)
338 {
339 try
340 {
341 final AttributeTypeDefinition at = new AttributeTypeDefinition(def);
342 s.add(at);
343 m.put(toLowerCase(at.getOID()), at);
344 for (final String name : at.getNames())
345 {
346 m.put(toLowerCase(name), at);
347 }
348
349 if (at.isOperational())
350 {
351 sOperational.add(at);
352 }
353 else
354 {
355 sUser.add(at);
356 }
357 }
358 catch (final LDAPException le)
359 {
360 debugException(le);
361 }
362 }
363
364 atMap = Collections.unmodifiableMap(m);
365 atSet = Collections.unmodifiableSet(s);
366 operationalATSet = Collections.unmodifiableSet(sOperational);
367 userATSet = Collections.unmodifiableSet(sUser);
368 }
369
370
371 // Decode the DIT content rules from the schema entry.
372 defs = schemaEntry.getAttributeValues(ATTR_DIT_CONTENT_RULE);
373 if (defs == null)
374 {
375 dcrMap = Collections.emptyMap();
376 dcrSet = Collections.emptySet();
377 }
378 else
379 {
380 final LinkedHashMap<String,DITContentRuleDefinition> m =
381 new LinkedHashMap<String,DITContentRuleDefinition>(2*defs.length);
382 final LinkedHashSet<DITContentRuleDefinition> s =
383 new LinkedHashSet<DITContentRuleDefinition>(defs.length);
384
385 for (final String def : defs)
386 {
387 try
388 {
389 final DITContentRuleDefinition dcr =
390 new DITContentRuleDefinition(def);
391 s.add(dcr);
392 m.put(toLowerCase(dcr.getOID()), dcr);
393 for (final String name : dcr.getNames())
394 {
395 m.put(toLowerCase(name), dcr);
396 }
397 }
398 catch (final LDAPException le)
399 {
400 debugException(le);
401 }
402 }
403
404 dcrMap = Collections.unmodifiableMap(m);
405 dcrSet = Collections.unmodifiableSet(s);
406 }
407
408
409 // Decode the DIT structure rules from the schema entry.
410 defs = schemaEntry.getAttributeValues(ATTR_DIT_STRUCTURE_RULE);
411 if (defs == null)
412 {
413 dsrMapByID = Collections.emptyMap();
414 dsrMapByName = Collections.emptyMap();
415 dsrMapByNameForm = Collections.emptyMap();
416 dsrSet = Collections.emptySet();
417 }
418 else
419 {
420 final LinkedHashMap<Integer,DITStructureRuleDefinition> mID =
421 new LinkedHashMap<Integer,DITStructureRuleDefinition>(defs.length);
422 final LinkedHashMap<String,DITStructureRuleDefinition> mN =
423 new LinkedHashMap<String,DITStructureRuleDefinition>(defs.length);
424 final LinkedHashMap<String,DITStructureRuleDefinition> mNF =
425 new LinkedHashMap<String,DITStructureRuleDefinition>(defs.length);
426 final LinkedHashSet<DITStructureRuleDefinition> s =
427 new LinkedHashSet<DITStructureRuleDefinition>(defs.length);
428
429 for (final String def : defs)
430 {
431 try
432 {
433 final DITStructureRuleDefinition dsr =
434 new DITStructureRuleDefinition(def);
435 s.add(dsr);
436 mID.put(dsr.getRuleID(), dsr);
437 mNF.put(toLowerCase(dsr.getNameFormID()), dsr);
438 for (final String name : dsr.getNames())
439 {
440 mN.put(toLowerCase(name), dsr);
441 }
442 }
443 catch (final LDAPException le)
444 {
445 debugException(le);
446 }
447 }
448
449 dsrMapByID = Collections.unmodifiableMap(mID);
450 dsrMapByName = Collections.unmodifiableMap(mN);
451 dsrMapByNameForm = Collections.unmodifiableMap(mNF);
452 dsrSet = Collections.unmodifiableSet(s);
453 }
454
455
456 // Decode the matching rules from the schema entry.
457 defs = schemaEntry.getAttributeValues(ATTR_MATCHING_RULE);
458 if (defs == null)
459 {
460 mrMap = Collections.emptyMap();
461 mrSet = Collections.emptySet();
462 }
463 else
464 {
465 final LinkedHashMap<String,MatchingRuleDefinition> m =
466 new LinkedHashMap<String,MatchingRuleDefinition>(2*defs.length);
467 final LinkedHashSet<MatchingRuleDefinition> s =
468 new LinkedHashSet<MatchingRuleDefinition>(defs.length);
469
470 for (final String def : defs)
471 {
472 try
473 {
474 final MatchingRuleDefinition mr = new MatchingRuleDefinition(def);
475 s.add(mr);
476 m.put(toLowerCase(mr.getOID()), mr);
477 for (final String name : mr.getNames())
478 {
479 m.put(toLowerCase(name), mr);
480 }
481 }
482 catch (final LDAPException le)
483 {
484 debugException(le);
485 }
486 }
487
488 mrMap = Collections.unmodifiableMap(m);
489 mrSet = Collections.unmodifiableSet(s);
490 }
491
492
493 // Decode the matching rule uses from the schema entry.
494 defs = schemaEntry.getAttributeValues(ATTR_MATCHING_RULE_USE);
495 if (defs == null)
496 {
497 mruMap = Collections.emptyMap();
498 mruSet = Collections.emptySet();
499 }
500 else
501 {
502 final LinkedHashMap<String,MatchingRuleUseDefinition> m =
503 new LinkedHashMap<String,MatchingRuleUseDefinition>(2*defs.length);
504 final LinkedHashSet<MatchingRuleUseDefinition> s =
505 new LinkedHashSet<MatchingRuleUseDefinition>(defs.length);
506
507 for (final String def : defs)
508 {
509 try
510 {
511 final MatchingRuleUseDefinition mru =
512 new MatchingRuleUseDefinition(def);
513 s.add(mru);
514 m.put(toLowerCase(mru.getOID()), mru);
515 for (final String name : mru.getNames())
516 {
517 m.put(toLowerCase(name), mru);
518 }
519 }
520 catch (final LDAPException le)
521 {
522 debugException(le);
523 }
524 }
525
526 mruMap = Collections.unmodifiableMap(m);
527 mruSet = Collections.unmodifiableSet(s);
528 }
529
530
531 // Decode the name forms from the schema entry.
532 defs = schemaEntry.getAttributeValues(ATTR_NAME_FORM);
533 if (defs == null)
534 {
535 nfMapByName = Collections.emptyMap();
536 nfMapByOC = Collections.emptyMap();
537 nfSet = Collections.emptySet();
538 }
539 else
540 {
541 final LinkedHashMap<String,NameFormDefinition> mN =
542 new LinkedHashMap<String,NameFormDefinition>(2*defs.length);
543 final LinkedHashMap<String,NameFormDefinition> mOC =
544 new LinkedHashMap<String,NameFormDefinition>(defs.length);
545 final LinkedHashSet<NameFormDefinition> s =
546 new LinkedHashSet<NameFormDefinition>(defs.length);
547
548 for (final String def : defs)
549 {
550 try
551 {
552 final NameFormDefinition nf = new NameFormDefinition(def);
553 s.add(nf);
554 mOC.put(toLowerCase(nf.getStructuralClass()), nf);
555 mN.put(toLowerCase(nf.getOID()), nf);
556 for (final String name : nf.getNames())
557 {
558 mN.put(toLowerCase(name), nf);
559 }
560 }
561 catch (final LDAPException le)
562 {
563 debugException(le);
564 }
565 }
566
567 nfMapByName = Collections.unmodifiableMap(mN);
568 nfMapByOC = Collections.unmodifiableMap(mOC);
569 nfSet = Collections.unmodifiableSet(s);
570 }
571
572
573 // Decode the object classes from the schema entry.
574 defs = schemaEntry.getAttributeValues(ATTR_OBJECT_CLASS);
575 if (defs == null)
576 {
577 ocMap = Collections.emptyMap();
578 ocSet = Collections.emptySet();
579 abstractOCSet = Collections.emptySet();
580 auxiliaryOCSet = Collections.emptySet();
581 structuralOCSet = Collections.emptySet();
582 }
583 else
584 {
585 final LinkedHashMap<String,ObjectClassDefinition> m =
586 new LinkedHashMap<String,ObjectClassDefinition>(2*defs.length);
587 final LinkedHashSet<ObjectClassDefinition> s =
588 new LinkedHashSet<ObjectClassDefinition>(defs.length);
589 final LinkedHashSet<ObjectClassDefinition> sAbstract =
590 new LinkedHashSet<ObjectClassDefinition>(defs.length);
591 final LinkedHashSet<ObjectClassDefinition> sAuxiliary =
592 new LinkedHashSet<ObjectClassDefinition>(defs.length);
593 final LinkedHashSet<ObjectClassDefinition> sStructural =
594 new LinkedHashSet<ObjectClassDefinition>(defs.length);
595
596 for (final String def : defs)
597 {
598 try
599 {
600 final ObjectClassDefinition oc = new ObjectClassDefinition(def);
601 s.add(oc);
602 m.put(toLowerCase(oc.getOID()), oc);
603 for (final String name : oc.getNames())
604 {
605 m.put(toLowerCase(name), oc);
606 }
607
608 switch (getOCType(oc, m))
609 {
610 case ABSTRACT:
611 sAbstract.add(oc);
612 break;
613 case AUXILIARY:
614 sAuxiliary.add(oc);
615 break;
616 case STRUCTURAL:
617 sStructural.add(oc);
618 break;
619 }
620 }
621 catch (final LDAPException le)
622 {
623 debugException(le);
624 }
625 }
626
627 ocMap = Collections.unmodifiableMap(m);
628 ocSet = Collections.unmodifiableSet(s);
629 abstractOCSet = Collections.unmodifiableSet(sAbstract);
630 auxiliaryOCSet = Collections.unmodifiableSet(sAuxiliary);
631 structuralOCSet = Collections.unmodifiableSet(sStructural);
632 }
633
634
635 // Populate the map of subordinate attribute types.
636 final LinkedHashMap<AttributeTypeDefinition,List<AttributeTypeDefinition>>
637 subAttrTypes = new LinkedHashMap<AttributeTypeDefinition,
638 List<AttributeTypeDefinition>>(atSet.size());
639 for (final AttributeTypeDefinition d : atSet)
640 {
641 AttributeTypeDefinition sup = d.getSuperiorType(this);
642 while (sup != null)
643 {
644 List<AttributeTypeDefinition> l = subAttrTypes.get(sup);
645 if (l == null)
646 {
647 l = new ArrayList<AttributeTypeDefinition>(1);
648 subAttrTypes.put(sup, l);
649 }
650 l.add(d);
651
652 sup = sup.getSuperiorType(this);
653 }
654 }
655 subordinateAttributeTypes = Collections.unmodifiableMap(subAttrTypes);
656 }
657
658
659
660 /**
661 * Retrieves the directory server schema over the provided connection. The
662 * root DSE will first be retrieved in order to get its subschemaSubentry DN,
663 * and then that entry will be retrieved from the server and its contents
664 * decoded as schema elements. This should be sufficient for directories that
665 * only provide a single schema, but for directories with multiple schemas it
666 * may be necessary to specify the DN of an entry for which to retrieve the
667 * subschema subentry.
668 *
669 * @param connection The connection to use in order to retrieve the server
670 * schema. It must not be {@code null}.
671 *
672 * @return A decoded representation of the server schema.
673 *
674 * @throws LDAPException If a problem occurs while obtaining the server
675 * schema.
676 */
677 public static Schema getSchema(final LDAPConnection connection)
678 throws LDAPException
679 {
680 return getSchema(connection, "");
681 }
682
683
684
685 /**
686 * Retrieves the directory server schema that governs the specified entry.
687 * In some servers, different portions of the DIT may be served by different
688 * schemas, and in such cases it will be necessary to provide the DN of the
689 * target entry in order to ensure that the appropriate schema which governs
690 * that entry is returned. For servers that support only a single schema,
691 * any entry DN (including that of the root DSE) should be sufficient.
692 *
693 * @param connection The connection to use in order to retrieve the server
694 * schema. It must not be {@code null}.
695 * @param entryDN The DN of the entry for which to retrieve the governing
696 * schema. It may be {@code null} or an empty string in
697 * order to retrieve the schema that governs the server's
698 * root DSE.
699 *
700 * @return A decoded representation of the server schema, or {@code null} if
701 * it is not available for some reason (e.g., the client does not
702 * have permission to read the server schema).
703 *
704 * @throws LDAPException If a problem occurs while obtaining the server
705 * schema.
706 */
707 public static Schema getSchema(final LDAPConnection connection,
708 final String entryDN)
709 throws LDAPException
710 {
711 ensureNotNull(connection);
712
713 final String subschemaSubentryDN;
714 if (entryDN == null)
715 {
716 subschemaSubentryDN = getSubschemaSubentryDN(connection, "");
717 }
718 else
719 {
720 subschemaSubentryDN = getSubschemaSubentryDN(connection, entryDN);
721 }
722
723 if (subschemaSubentryDN == null)
724 {
725 return null;
726 }
727
728 final Entry schemaEntry = connection.searchForEntry(subschemaSubentryDN,
729 SearchScope.BASE,
730 Filter.createEqualityFilter("objectClass", "subschema"),
731 SCHEMA_REQUEST_ATTRS);
732 if (schemaEntry == null)
733 {
734 return null;
735 }
736
737 return new Schema(schemaEntry);
738 }
739
740
741
742 /**
743 * Reads schema information from one or more files containing the schema
744 * represented in LDIF form, with the definitions represented in the form
745 * described in section 4.1 of RFC 4512. Each file should contain a single
746 * entry.
747 *
748 * @param schemaFiles The paths to the LDIF files containing the schema
749 * information to be read. At least one file must be
750 * specified. If multiple files are specified, then they
751 * will be processed in the order in which they have been
752 * listed.
753 *
754 * @return The schema read from the specified schema files, or {@code null}
755 * if none of the files contains any LDIF data to be read.
756 *
757 * @throws IOException If a problem occurs while attempting to read from
758 * any of the specified files.
759 *
760 * @throws LDIFException If a problem occurs while attempting to parse the
761 * contents of any of the schema files.
762 */
763 public static Schema getSchema(final String... schemaFiles)
764 throws IOException, LDIFException
765 {
766 ensureNotNull(schemaFiles);
767 ensureFalse(schemaFiles.length == 0);
768
769 final ArrayList<File> files = new ArrayList<File>(schemaFiles.length);
770 for (final String s : schemaFiles)
771 {
772 files.add(new File(s));
773 }
774
775 return getSchema(files);
776 }
777
778
779
780 /**
781 * Reads schema information from one or more files containing the schema
782 * represented in LDIF form, with the definitions represented in the form
783 * described in section 4.1 of RFC 4512. Each file should contain a single
784 * entry.
785 *
786 * @param schemaFiles The paths to the LDIF files containing the schema
787 * information to be read. At least one file must be
788 * specified. If multiple files are specified, then they
789 * will be processed in the order in which they have been
790 * listed.
791 *
792 * @return The schema read from the specified schema files, or {@code null}
793 * if none of the files contains any LDIF data to be read.
794 *
795 * @throws IOException If a problem occurs while attempting to read from
796 * any of the specified files.
797 *
798 * @throws LDIFException If a problem occurs while attempting to parse the
799 * contents of any of the schema files.
800 */
801 public static Schema getSchema(final File... schemaFiles)
802 throws IOException, LDIFException
803 {
804 ensureNotNull(schemaFiles);
805 ensureFalse(schemaFiles.length == 0);
806
807 return getSchema(Arrays.asList(schemaFiles));
808 }
809
810
811
812 /**
813 * Reads schema information from one or more files containing the schema
814 * represented in LDIF form, with the definitions represented in the form
815 * described in section 4.1 of RFC 4512. Each file should contain a single
816 * entry.
817 *
818 * @param schemaFiles The paths to the LDIF files containing the schema
819 * information to be read. At least one file must be
820 * specified. If multiple files are specified, then they
821 * will be processed in the order in which they have been
822 * listed.
823 *
824 * @return The schema read from the specified schema files, or {@code null}
825 * if none of the files contains any LDIF data to be read.
826 *
827 * @throws IOException If a problem occurs while attempting to read from
828 * any of the specified files.
829 *
830 * @throws LDIFException If a problem occurs while attempting to parse the
831 * contents of any of the schema files.
832 */
833 public static Schema getSchema(final List<File> schemaFiles)
834 throws IOException, LDIFException
835 {
836 ensureNotNull(schemaFiles);
837 ensureFalse(schemaFiles.isEmpty());
838
839 Entry schemaEntry = null;
840 for (final File f : schemaFiles)
841 {
842 final LDIFReader ldifReader = new LDIFReader(f);
843
844 try
845 {
846 final Entry e = ldifReader.readEntry();
847 if (e == null)
848 {
849 continue;
850 }
851
852 e.addAttribute("objectClass", "top", "ldapSubentry", "subschema");
853
854 if (schemaEntry == null)
855 {
856 schemaEntry = e;
857 }
858 else
859 {
860 for (final Attribute a : e.getAttributes())
861 {
862 schemaEntry.addAttribute(a);
863 }
864 }
865 }
866 finally
867 {
868 ldifReader.close();
869 }
870 }
871
872 if (schemaEntry == null)
873 {
874 return null;
875 }
876
877 return new Schema(schemaEntry);
878 }
879
880
881
882 /**
883 * Retrieves a schema object that contains definitions for a number of
884 * standard attribute types and object classes from LDAP-related RFCs and
885 * Internet Drafts.
886 *
887 * @return A schema object that contains definitions for a number of standard
888 * attribute types and object classes from LDAP-related RFCs and
889 * Internet Drafts.
890 *
891 * @throws LDAPException If a problem occurs while attempting to obtain or
892 * parse the default standard schema definitions.
893 */
894 public static Schema getDefaultStandardSchema()
895 throws LDAPException
896 {
897 final Schema s = DEFAULT_STANDARD_SCHEMA.get();
898 if (s != null)
899 {
900 return s;
901 }
902
903 synchronized (DEFAULT_STANDARD_SCHEMA)
904 {
905 try
906 {
907 final ClassLoader classLoader = Schema.class.getClassLoader();
908 final InputStream inputStream =
909 classLoader.getResourceAsStream(DEFAULT_SCHEMA_RESOURCE_PATH);
910 final LDIFReader ldifReader = new LDIFReader(inputStream);
911 final Entry schemaEntry = ldifReader.readEntry();
912 ldifReader.close();
913
914 final Schema schema = new Schema(schemaEntry);
915 DEFAULT_STANDARD_SCHEMA.set(schema);
916 return schema;
917 }
918 catch (final Exception e)
919 {
920 debugException(e);
921 throw new LDAPException(ResultCode.LOCAL_ERROR,
922 ERR_SCHEMA_CANNOT_LOAD_DEFAULT_DEFINITIONS.get(
923 getExceptionMessage(e)),
924 e);
925 }
926 }
927 }
928
929
930
931 /**
932 * Retrieves a schema containing all of the elements of each of the provided
933 * schemas.
934 *
935 * @param schemas The schemas to be merged. It must not be {@code null} or
936 * empty.
937 *
938 * @return A merged representation of the provided schemas.
939 */
940 public static Schema mergeSchemas(final Schema... schemas)
941 {
942 if ((schemas == null) || (schemas.length == 0))
943 {
944 return null;
945 }
946 else if (schemas.length == 1)
947 {
948 return schemas[0];
949 }
950
951 final LinkedHashMap<String,String> asMap =
952 new LinkedHashMap<String,String>();
953 final LinkedHashMap<String,String> atMap =
954 new LinkedHashMap<String,String>();
955 final LinkedHashMap<String,String> dcrMap =
956 new LinkedHashMap<String,String>();
957 final LinkedHashMap<Integer,String> dsrMap =
958 new LinkedHashMap<Integer,String>();
959 final LinkedHashMap<String,String> mrMap =
960 new LinkedHashMap<String,String>();
961 final LinkedHashMap<String,String> mruMap =
962 new LinkedHashMap<String,String>();
963 final LinkedHashMap<String,String> nfMap =
964 new LinkedHashMap<String,String>();
965 final LinkedHashMap<String,String> ocMap =
966 new LinkedHashMap<String,String>();
967
968 for (final Schema s : schemas)
969 {
970 for (final AttributeSyntaxDefinition as : s.asSet)
971 {
972 asMap.put(toLowerCase(as.getOID()), as.toString());
973 }
974
975 for (final AttributeTypeDefinition at : s.atSet)
976 {
977 atMap.put(toLowerCase(at.getOID()), at.toString());
978 }
979
980 for (final DITContentRuleDefinition dcr : s.dcrSet)
981 {
982 dcrMap.put(toLowerCase(dcr.getOID()), dcr.toString());
983 }
984
985 for (final DITStructureRuleDefinition dsr : s.dsrSet)
986 {
987 dsrMap.put(dsr.getRuleID(), dsr.toString());
988 }
989
990 for (final MatchingRuleDefinition mr : s.mrSet)
991 {
992 mrMap.put(toLowerCase(mr.getOID()), mr.toString());
993 }
994
995 for (final MatchingRuleUseDefinition mru : s.mruSet)
996 {
997 mruMap.put(toLowerCase(mru.getOID()), mru.toString());
998 }
999
1000 for (final NameFormDefinition nf : s.nfSet)
1001 {
1002 nfMap.put(toLowerCase(nf.getOID()), nf.toString());
1003 }
1004
1005 for (final ObjectClassDefinition oc : s.ocSet)
1006 {
1007 ocMap.put(toLowerCase(oc.getOID()), oc.toString());
1008 }
1009 }
1010
1011 final Entry e = new Entry(schemas[0].getSchemaEntry().getDN());
1012
1013 final Attribute ocAttr =
1014 schemas[0].getSchemaEntry().getObjectClassAttribute();
1015 if (ocAttr == null)
1016 {
1017 e.addAttribute("objectClass", "top", "ldapSubEntry", "subschema");
1018 }
1019 else
1020 {
1021 e.addAttribute(ocAttr);
1022 }
1023
1024 if (! asMap.isEmpty())
1025 {
1026 final String[] values = new String[asMap.size()];
1027 e.addAttribute(ATTR_ATTRIBUTE_SYNTAX, asMap.values().toArray(values));
1028 }
1029
1030 if (! mrMap.isEmpty())
1031 {
1032 final String[] values = new String[mrMap.size()];
1033 e.addAttribute(ATTR_MATCHING_RULE, mrMap.values().toArray(values));
1034 }
1035
1036 if (! atMap.isEmpty())
1037 {
1038 final String[] values = new String[atMap.size()];
1039 e.addAttribute(ATTR_ATTRIBUTE_TYPE, atMap.values().toArray(values));
1040 }
1041
1042 if (! ocMap.isEmpty())
1043 {
1044 final String[] values = new String[ocMap.size()];
1045 e.addAttribute(ATTR_OBJECT_CLASS, ocMap.values().toArray(values));
1046 }
1047
1048 if (! dcrMap.isEmpty())
1049 {
1050 final String[] values = new String[dcrMap.size()];
1051 e.addAttribute(ATTR_DIT_CONTENT_RULE, dcrMap.values().toArray(values));
1052 }
1053
1054 if (! dsrMap.isEmpty())
1055 {
1056 final String[] values = new String[dsrMap.size()];
1057 e.addAttribute(ATTR_DIT_STRUCTURE_RULE, dsrMap.values().toArray(values));
1058 }
1059
1060 if (! nfMap.isEmpty())
1061 {
1062 final String[] values = new String[nfMap.size()];
1063 e.addAttribute(ATTR_NAME_FORM, nfMap.values().toArray(values));
1064 }
1065
1066 if (! mruMap.isEmpty())
1067 {
1068 final String[] values = new String[mruMap.size()];
1069 e.addAttribute(ATTR_MATCHING_RULE_USE, mruMap.values().toArray(values));
1070 }
1071
1072 return new Schema(e);
1073 }
1074
1075
1076
1077 /**
1078 * Retrieves the entry used to create this schema object.
1079 *
1080 * @return The entry used to create this schema object.
1081 */
1082 public ReadOnlyEntry getSchemaEntry()
1083 {
1084 return schemaEntry;
1085 }
1086
1087
1088
1089 /**
1090 * Retrieves the object class type for the specified object class, recursively
1091 * checking its parents as needed.
1092 *
1093 * @param oc The object class definition for which to make the
1094 * determination.
1095 * @param m The map of defined object classes.
1096 *
1097 * @return The object class type for the object class.
1098 */
1099 private static ObjectClassType getOCType(final ObjectClassDefinition oc,
1100 final Map<String,ObjectClassDefinition> m)
1101 {
1102 ObjectClassType t = oc.getObjectClassType();
1103 if (t != null)
1104 {
1105 return t;
1106 }
1107
1108 for (final String s : oc.getSuperiorClasses())
1109 {
1110 final ObjectClassDefinition d = m.get(toLowerCase(s));
1111 if (d != null)
1112 {
1113 t = getOCType(d, m);
1114 if (t != null)
1115 {
1116 return t;
1117 }
1118 }
1119 }
1120
1121 return ObjectClassType.STRUCTURAL;
1122 }
1123
1124
1125
1126 /**
1127 * Retrieves the value of the subschemaSubentry attribute from the specified
1128 * entry using the provided connection.
1129 *
1130 * @param connection The connection to use in order to perform the search.
1131 * It must not be {@code null}.
1132 * @param entryDN The DN of the entry from which to retrieve the
1133 * subschemaSubentry attribute. It may be {@code null} or
1134 * an empty string in order to retrieve the value from the
1135 * server's root DSE.
1136 *
1137 * @return The value of the subschemaSubentry attribute from the specified
1138 * entry, or {@code null} if it is not available for some reason
1139 * (e.g., the client does not have permission to read the target
1140 * entry or the subschemaSubentry attribute).
1141 *
1142 * @throws LDAPException If a problem occurs while attempting to retrieve
1143 * the specified entry.
1144 */
1145 public static String getSubschemaSubentryDN(final LDAPConnection connection,
1146 final String entryDN)
1147 throws LDAPException
1148 {
1149 ensureNotNull(connection);
1150
1151 final Entry e;
1152 if (entryDN == null)
1153 {
1154 e = connection.getEntry("", SUBSCHEMA_SUBENTRY_REQUEST_ATTRS);
1155 }
1156 else
1157 {
1158 e = connection.getEntry(entryDN, SUBSCHEMA_SUBENTRY_REQUEST_ATTRS);
1159 }
1160
1161 if (e == null)
1162 {
1163 return null;
1164 }
1165
1166 return e.getAttributeValue(ATTR_SUBSCHEMA_SUBENTRY);
1167 }
1168
1169
1170
1171 /**
1172 * Retrieves the set of attribute syntax definitions contained in the server
1173 * schema.
1174 *
1175 * @return The set of attribute syntax definitions contained in the server
1176 * schema.
1177 */
1178 public Set<AttributeSyntaxDefinition> getAttributeSyntaxes()
1179 {
1180 return asSet;
1181 }
1182
1183
1184
1185 /**
1186 * Retrieves the attribute syntax with the specified OID from the server
1187 * schema.
1188 *
1189 * @param oid The OID of the attribute syntax to retrieve. It must not be
1190 * {@code null}. It may optionally include a minimum upper bound
1191 * (as may appear when the syntax OID is included in an attribute
1192 * type definition), but if it does then that portion will be
1193 * ignored when retrieving the attribute syntax.
1194 *
1195 * @return The requested attribute syntax, or {@code null} if there is no
1196 * such syntax defined in the server schema.
1197 */
1198 public AttributeSyntaxDefinition getAttributeSyntax(final String oid)
1199 {
1200 ensureNotNull(oid);
1201
1202 final String lowerOID = toLowerCase(oid);
1203 final int curlyPos = lowerOID.indexOf('{');
1204
1205 if (curlyPos > 0)
1206 {
1207 return asMap.get(lowerOID.substring(0, curlyPos));
1208 }
1209 else
1210 {
1211 return asMap.get(lowerOID);
1212 }
1213 }
1214
1215
1216
1217 /**
1218 * Retrieves the set of attribute type definitions contained in the server
1219 * schema.
1220 *
1221 * @return The set of attribute type definitions contained in the server
1222 * schema.
1223 */
1224 public Set<AttributeTypeDefinition> getAttributeTypes()
1225 {
1226 return atSet;
1227 }
1228
1229
1230
1231 /**
1232 * Retrieves the set of operational attribute type definitions (i.e., those
1233 * definitions with a usage of directoryOperation, distributedOperation, or
1234 * dSAOperation) contained in the server schema.
1235 *
1236 * @return The set of operational attribute type definitions contained in the
1237 * server schema.
1238 */
1239 public Set<AttributeTypeDefinition> getOperationalAttributeTypes()
1240 {
1241 return operationalATSet;
1242 }
1243
1244
1245
1246 /**
1247 * Retrieves the set of user attribute type definitions (i.e., those
1248 * definitions with a usage of userApplications) contained in the server
1249 * schema.
1250 *
1251 * @return The set of user attribute type definitions contained in the server
1252 * schema.
1253 */
1254 public Set<AttributeTypeDefinition> getUserAttributeTypes()
1255 {
1256 return userATSet;
1257 }
1258
1259
1260
1261 /**
1262 * Retrieves the attribute type with the specified name or OID from the server
1263 * schema.
1264 *
1265 * @param name The name or OID of the attribute type to retrieve. It must
1266 * not be {@code null}.
1267 *
1268 * @return The requested attribute type, or {@code null} if there is no
1269 * such attribute type defined in the server schema.
1270 */
1271 public AttributeTypeDefinition getAttributeType(final String name)
1272 {
1273 ensureNotNull(name);
1274
1275 return atMap.get(toLowerCase(name));
1276 }
1277
1278
1279
1280 /**
1281 * Retrieves a list of all subordinate attribute type definitions for the
1282 * provided attribute type definition.
1283 *
1284 * @param d The attribute type definition for which to retrieve all
1285 * subordinate attribute types. It must not be {@code null}.
1286 *
1287 * @return A list of all subordinate attribute type definitions for the
1288 * provided attribute type definition, or an empty list if it does
1289 * not have any subordinate types or the provided attribute type is
1290 * not defined in the schema.
1291 */
1292 public List<AttributeTypeDefinition> getSubordinateAttributeTypes(
1293 final AttributeTypeDefinition d)
1294 {
1295 ensureNotNull(d);
1296
1297 final List<AttributeTypeDefinition> l = subordinateAttributeTypes.get(d);
1298 if (l == null)
1299 {
1300 return Collections.emptyList();
1301 }
1302 else
1303 {
1304 return Collections.unmodifiableList(l);
1305 }
1306 }
1307
1308
1309
1310 /**
1311 * Retrieves the set of DIT content rule definitions contained in the server
1312 * schema.
1313 *
1314 * @return The set of DIT content rule definitions contained in the server
1315 * schema.
1316 */
1317 public Set<DITContentRuleDefinition> getDITContentRules()
1318 {
1319 return dcrSet;
1320 }
1321
1322
1323
1324 /**
1325 * Retrieves the DIT content rule with the specified name or OID from the
1326 * server schema.
1327 *
1328 * @param name The name or OID of the DIT content rule to retrieve. It must
1329 * not be {@code null}.
1330 *
1331 * @return The requested DIT content rule, or {@code null} if there is no
1332 * such rule defined in the server schema.
1333 */
1334 public DITContentRuleDefinition getDITContentRule(final String name)
1335 {
1336 ensureNotNull(name);
1337
1338 return dcrMap.get(toLowerCase(name));
1339 }
1340
1341
1342
1343 /**
1344 * Retrieves the set of DIT structure rule definitions contained in the server
1345 * schema.
1346 *
1347 * @return The set of DIT structure rule definitions contained in the server
1348 * schema.
1349 */
1350 public Set<DITStructureRuleDefinition> getDITStructureRules()
1351 {
1352 return dsrSet;
1353 }
1354
1355
1356
1357 /**
1358 * Retrieves the DIT content rule with the specified rule ID from the server
1359 * schema.
1360 *
1361 * @param ruleID The rule ID for the DIT structure rule to retrieve.
1362 *
1363 * @return The requested DIT structure rule, or {@code null} if there is no
1364 * such rule defined in the server schema.
1365 */
1366 public DITStructureRuleDefinition getDITStructureRuleByID(final int ruleID)
1367 {
1368 return dsrMapByID.get(ruleID);
1369 }
1370
1371
1372
1373 /**
1374 * Retrieves the DIT content rule with the specified name from the server
1375 * schema.
1376 *
1377 * @param ruleName The name of the DIT structure rule to retrieve. It must
1378 * not be {@code null}.
1379 *
1380 * @return The requested DIT structure rule, or {@code null} if there is no
1381 * such rule defined in the server schema.
1382 */
1383 public DITStructureRuleDefinition getDITStructureRuleByName(
1384 final String ruleName)
1385 {
1386 ensureNotNull(ruleName);
1387
1388 return dsrMapByName.get(toLowerCase(ruleName));
1389 }
1390
1391
1392
1393 /**
1394 * Retrieves the DIT content rule associated with the specified name form from
1395 * the server schema.
1396 *
1397 * @param nameForm The name or OID of the name form for which to retrieve
1398 * the associated DIT structure rule.
1399 *
1400 * @return The requested DIT structure rule, or {@code null} if there is no
1401 * such rule defined in the server schema.
1402 */
1403 public DITStructureRuleDefinition getDITStructureRuleByNameForm(
1404 final String nameForm)
1405 {
1406 ensureNotNull(nameForm);
1407
1408 return dsrMapByNameForm.get(toLowerCase(nameForm));
1409 }
1410
1411
1412
1413 /**
1414 * Retrieves the set of matching rule definitions contained in the server
1415 * schema.
1416 *
1417 * @return The set of matching rule definitions contained in the server
1418 * schema.
1419 */
1420 public Set<MatchingRuleDefinition> getMatchingRules()
1421 {
1422 return mrSet;
1423 }
1424
1425
1426
1427 /**
1428 * Retrieves the matching rule with the specified name or OID from the server
1429 * schema.
1430 *
1431 * @param name The name or OID of the matching rule to retrieve. It must
1432 * not be {@code null}.
1433 *
1434 * @return The requested matching rule, or {@code null} if there is no
1435 * such rule defined in the server schema.
1436 */
1437 public MatchingRuleDefinition getMatchingRule(final String name)
1438 {
1439 ensureNotNull(name);
1440
1441 return mrMap.get(toLowerCase(name));
1442 }
1443
1444
1445
1446 /**
1447 * Retrieves the set of matching rule use definitions contained in the server
1448 * schema.
1449 *
1450 * @return The set of matching rule use definitions contained in the server
1451 * schema.
1452 */
1453 public Set<MatchingRuleUseDefinition> getMatchingRuleUses()
1454 {
1455 return mruSet;
1456 }
1457
1458
1459
1460 /**
1461 * Retrieves the matching rule use with the specified name or OID from the
1462 * server schema.
1463 *
1464 * @param name The name or OID of the matching rule use to retrieve. It
1465 * must not be {@code null}.
1466 *
1467 * @return The requested matching rule, or {@code null} if there is no
1468 * such matching rule use defined in the server schema.
1469 */
1470 public MatchingRuleUseDefinition getMatchingRuleUse(final String name)
1471 {
1472 ensureNotNull(name);
1473
1474 return mruMap.get(toLowerCase(name));
1475 }
1476
1477
1478
1479 /**
1480 * Retrieves the set of name form definitions contained in the server schema.
1481 *
1482 * @return The set of name form definitions contained in the server schema.
1483 */
1484 public Set<NameFormDefinition> getNameForms()
1485 {
1486 return nfSet;
1487 }
1488
1489
1490
1491 /**
1492 * Retrieves the name form with the specified name or OID from the server
1493 * schema.
1494 *
1495 * @param name The name or OID of the name form to retrieve. It must not be
1496 * {@code null}.
1497 *
1498 * @return The requested name form, or {@code null} if there is no
1499 * such rule defined in the server schema.
1500 */
1501 public NameFormDefinition getNameFormByName(final String name)
1502 {
1503 ensureNotNull(name);
1504
1505 return nfMapByName.get(toLowerCase(name));
1506 }
1507
1508
1509
1510 /**
1511 * Retrieves the name form associated with the specified structural object
1512 * class from the server schema.
1513 *
1514 * @param objectClass The name or OID of the structural object class for
1515 * which to retrieve the associated name form. It must
1516 * not be {@code null}.
1517 *
1518 * @return The requested name form, or {@code null} if there is no
1519 * such rule defined in the server schema.
1520 */
1521 public NameFormDefinition getNameFormByObjectClass(final String objectClass)
1522 {
1523 ensureNotNull(objectClass);
1524
1525 return nfMapByOC.get(toLowerCase(objectClass));
1526 }
1527
1528
1529
1530 /**
1531 * Retrieves the set of object class definitions contained in the server
1532 * schema.
1533 *
1534 * @return The set of object class definitions contained in the server
1535 * schema.
1536 */
1537 public Set<ObjectClassDefinition> getObjectClasses()
1538 {
1539 return ocSet;
1540 }
1541
1542
1543
1544 /**
1545 * Retrieves the set of abstract object class definitions contained in the
1546 * server schema.
1547 *
1548 * @return The set of abstract object class definitions contained in the
1549 * server schema.
1550 */
1551 public Set<ObjectClassDefinition> getAbstractObjectClasses()
1552 {
1553 return abstractOCSet;
1554 }
1555
1556
1557
1558 /**
1559 * Retrieves the set of auxiliary object class definitions contained in the
1560 * server schema.
1561 *
1562 * @return The set of auxiliary object class definitions contained in the
1563 * server schema.
1564 */
1565 public Set<ObjectClassDefinition> getAuxiliaryObjectClasses()
1566 {
1567 return auxiliaryOCSet;
1568 }
1569
1570
1571
1572 /**
1573 * Retrieves the set of structural object class definitions contained in the
1574 * server schema.
1575 *
1576 * @return The set of structural object class definitions contained in the
1577 * server schema.
1578 */
1579 public Set<ObjectClassDefinition> getStructuralObjectClasses()
1580 {
1581 return structuralOCSet;
1582 }
1583
1584
1585
1586 /**
1587 * Retrieves the object class with the specified name or OID from the server
1588 * schema.
1589 *
1590 * @param name The name or OID of the object class to retrieve. It must
1591 * not be {@code null}.
1592 *
1593 * @return The requested object class, or {@code null} if there is no such
1594 * class defined in the server schema.
1595 */
1596 public ObjectClassDefinition getObjectClass(final String name)
1597 {
1598 ensureNotNull(name);
1599
1600 return ocMap.get(toLowerCase(name));
1601 }
1602
1603
1604
1605 /**
1606 * Retrieves a hash code for this schema object.
1607 *
1608 * @return A hash code for this schema object.
1609 */
1610 @Override()
1611 public int hashCode()
1612 {
1613 int hc;
1614 try
1615 {
1616 hc = schemaEntry.getParsedDN().hashCode();
1617 }
1618 catch (final Exception e)
1619 {
1620 debugException(e);
1621 hc = toLowerCase(schemaEntry.getDN()).hashCode();
1622 }
1623
1624 Attribute a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_SYNTAX);
1625 if (a != null)
1626 {
1627 hc += a.hashCode();
1628 }
1629
1630 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE);
1631 if (a != null)
1632 {
1633 hc += a.hashCode();
1634 }
1635
1636 a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_TYPE);
1637 if (a != null)
1638 {
1639 hc += a.hashCode();
1640 }
1641
1642 a = schemaEntry.getAttribute(ATTR_OBJECT_CLASS);
1643 if (a != null)
1644 {
1645 hc += a.hashCode();
1646 }
1647
1648 a = schemaEntry.getAttribute(ATTR_NAME_FORM);
1649 if (a != null)
1650 {
1651 hc += a.hashCode();
1652 }
1653
1654 a = schemaEntry.getAttribute(ATTR_DIT_CONTENT_RULE);
1655 if (a != null)
1656 {
1657 hc += a.hashCode();
1658 }
1659
1660 a = schemaEntry.getAttribute(ATTR_DIT_STRUCTURE_RULE);
1661 if (a != null)
1662 {
1663 hc += a.hashCode();
1664 }
1665
1666 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE_USE);
1667 if (a != null)
1668 {
1669 hc += a.hashCode();
1670 }
1671
1672 return hc;
1673 }
1674
1675
1676
1677 /**
1678 * Indicates whether the provided object is equal to this schema object.
1679 *
1680 * @param o The object for which to make the determination.
1681 *
1682 * @return {@code true} if the provided object is equal to this schema
1683 * object, or {@code false} if not.
1684 */
1685 @Override()
1686 public boolean equals(final Object o)
1687 {
1688 if (o == null)
1689 {
1690 return false;
1691 }
1692
1693 if (o == this)
1694 {
1695 return true;
1696 }
1697
1698 if (! (o instanceof Schema))
1699 {
1700 return false;
1701 }
1702
1703 final Schema s = (Schema) o;
1704
1705 try
1706 {
1707 if (! schemaEntry.getParsedDN().equals(s.schemaEntry.getParsedDN()))
1708 {
1709 return false;
1710 }
1711 }
1712 catch (final Exception e)
1713 {
1714 debugException(e);
1715 if (! schemaEntry.getDN().equalsIgnoreCase(s.schemaEntry.getDN()))
1716 {
1717 return false;
1718 }
1719 }
1720
1721 return (asSet.equals(s.asSet) &&
1722 mrSet.equals(s.mrSet) &&
1723 atSet.equals(s.atSet) &&
1724 ocSet.equals(s.ocSet) &&
1725 nfSet.equals(s.nfSet) &&
1726 dcrSet.equals(s.dcrSet) &&
1727 dsrSet.equals(s.dsrSet) &&
1728 mruSet.equals(s.mruSet));
1729 }
1730
1731
1732
1733 /**
1734 * Retrieves a string representation of the associated schema entry.
1735 *
1736 * @return A string representation of the associated schema entry.
1737 */
1738 @Override()
1739 public String toString()
1740 {
1741 return schemaEntry.toString();
1742 }
1743 }