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