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