001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.types;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.Collection;
033 import java.util.List;
034 import java.util.Map;
035
036 import org.opends.server.api.ApproximateMatchingRule;
037 import org.opends.server.api.AttributeSyntax;
038 import org.opends.server.api.EqualityMatchingRule;
039 import org.opends.server.api.OrderingMatchingRule;
040 import org.opends.server.api.SubstringMatchingRule;
041 import org.opends.server.core.DirectoryServer;
042 import org.opends.server.schema.AttributeTypeSyntax;
043
044 import static org.opends.server.loggers.debug.DebugLogger.*;
045 import org.opends.server.loggers.debug.DebugTracer;
046 import static org.opends.messages.CoreMessages.*;
047 import static org.opends.server.util.ServerConstants.*;
048 import static org.opends.server.util.Validator.*;
049
050
051
052 /**
053 * This class defines a data structure for storing and interacting
054 * with an attribute type, which contains information about the format
055 * of an attribute and the syntax and matching rules that should be
056 * used when interacting with it.
057 * <p>
058 * Any methods which accesses the set of names associated with this
059 * attribute type, will retrieve the primary name as the first name,
060 * regardless of whether or not it was contained in the original set
061 * of <code>names</code> passed to the constructor.
062 * <p>
063 * Where ordered sets of names, or extra properties are provided, the
064 * ordering will be preserved when the associated fields are accessed
065 * via their getters or via the {@link #toString()} methods.
066 */
067 @org.opends.server.types.PublicAPI(
068 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
069 mayInstantiate=false,
070 mayExtend=false,
071 mayInvoke=true)
072 public final class AttributeType
073 extends CommonSchemaElements
074 implements SchemaFileElement
075 {
076 /**
077 * The tracer object for the debug logger.
078 */
079 private static final DebugTracer TRACER = getTracer();
080
081 // The approximate matching rule for this attribute type.
082 private final ApproximateMatchingRule approximateMatchingRule;
083
084 // The syntax for this attribute type.
085 private final AttributeSyntax syntax;
086
087 // The superior attribute type from which this attribute type
088 // inherits.
089 private final AttributeType superiorType;
090
091 // The attribute usage for this attribute type.
092 private final AttributeUsage attributeUsage;
093
094 // Indicates whether this attribute type is declared "collective".
095 private final boolean isCollective;
096
097 // Indicates whether this attribute type is declared
098 // "no-user-modification".
099 private final boolean isNoUserModification;
100
101 // Indicates whether this attribute type is the objectclass type.
102 private final boolean isObjectClassType;
103
104 // Indicates whether this attribute type is operational.
105 private final boolean isOperational;
106
107 // Indicates whether this attribute type is declared "single-value".
108 private final boolean isSingleValue;
109
110 // Indicates whether there is a possibility that this attribute type
111 // may have one or more subtypes that list this type or one of its
112 // subtypes as a superior. Note that this variable is intentional
113 // not declared "final", but if it ever gets set to "true", then it
114 // should never be unset back to "false".
115 private boolean mayHaveSubordinateTypes;
116
117 // The equality matching rule for this attribute type.
118 private final EqualityMatchingRule equalityMatchingRule;
119
120 // The ordering matching rule for this attribute type.
121 private final OrderingMatchingRule orderingMatchingRule;
122
123 // The definition string used to create this attribute type.
124 private final String definition;
125
126 // The OID for the associated syntax.
127 private final String syntaxOID;
128
129 // The substring matching rule for this attribute type.
130 private final SubstringMatchingRule substringMatchingRule;
131
132
133
134 /**
135 * Creates a new attribute type with the provided information.
136 * <p>
137 * If no <code>primaryName</code> is specified, but a set of
138 * <code>names</code> is specified, then the first name retrieved
139 * from the set of <code>names</code> will be used as the primary
140 * name.
141 *
142 * @param definition
143 * The definition string used to create this attribute
144 * type. It must not be {@code null}.
145 * @param primaryName
146 * The primary name for this attribute type, or
147 * <code>null</code> if there is no primary name.
148 * @param typeNames
149 * The full set of names for this attribute type, or
150 * <code>null</code> if there are no names.
151 * @param oid
152 * The OID for this attribute type. It must not be
153 * {@code null}.
154 * @param description
155 * The description for the attribute type, or
156 * <code>null</code> if there is no description.
157 * @param superiorType
158 * The reference to the superior type for this attribute
159 * type, or <code>null</code> if there is no superior
160 * type.
161 * @param syntax
162 * The syntax for this attribute type, or <code>null</code>
163 * if there is no syntax.
164 * @param attributeUsage
165 * The attribute usage for this attribute type, or
166 * <code>null</code> to default to user applications.
167 * @param isCollective
168 * Indicates whether this attribute type is declared
169 * "collective".
170 * @param isNoUserModification
171 * Indicates whether this attribute type is declared
172 * "no-user-modification".
173 * @param isObsolete
174 * Indicates whether this attribute type is declared
175 * "obsolete".
176 * @param isSingleValue
177 * Indicates whether this attribute type is declared
178 * "single-value".
179 */
180 public AttributeType(String definition, String primaryName,
181 Collection<String> typeNames,
182 String oid, String description,
183 AttributeType superiorType,
184 AttributeSyntax syntax,
185 AttributeUsage attributeUsage,
186 boolean isCollective,
187 boolean isNoUserModification,
188 boolean isObsolete, boolean isSingleValue)
189 {
190 this(definition, primaryName, typeNames, oid, description,
191 superiorType, syntax, null, null, null,
192 null, attributeUsage, isCollective,
193 isNoUserModification, isObsolete, isSingleValue, null);
194 }
195
196
197
198 /**
199 * Creates a new attribute type with the provided information.
200 * <p>
201 * If no <code>primaryName</code> is specified, but a set of
202 * <code>names</code> is specified, then the first name retrieved
203 * from the set of <code>names</code> will be used as the primary
204 * name.
205 *
206 * @param definition
207 * The definition string used to create this attribute
208 * type. It must not be {@code null}.
209 * @param primaryName
210 * The primary name for this attribute type, or
211 * <code>null</code> if there is no primary name.
212 * @param typeNames
213 * The full set of names for this attribute type, or
214 * <code>null</code> if there are no names.
215 * @param oid
216 * The OID for this attribute type. It must not be
217 * {@code null}.
218 * @param description
219 * The description for the attribute type, or
220 * <code>null</code> if there is no description.
221 * @param superiorType
222 * The reference to the superior type for this attribute
223 * type, or <code>null</code> if there is no superior
224 * type.
225 * @param syntax
226 * The syntax for this attribute type, or <code>null</code>
227 * if there is no syntax.
228 * @param approximateMatchingRule
229 * The approximate matching rule for this attribute type,
230 * or <code>null</code> if there is no rule.
231 * @param equalityMatchingRule
232 * The equality matching rule for this attribute type, or
233 * <code>null</code> if there is no rule.
234 * @param orderingMatchingRule
235 * The ordering matching rule for this attribute type, or
236 * <code>null</code> if there is no rule.
237 * @param substringMatchingRule
238 * The substring matching rule for this attribute type, or
239 * <code>null</code> if there is no rule.
240 * @param attributeUsage
241 * The attribute usage for this attribute type, or
242 * <code>null</code> to default to user applications.
243 * @param isCollective
244 * Indicates whether this attribute type is declared
245 * "collective".
246 * @param isNoUserModification
247 * Indicates whether this attribute type is declared
248 * "no-user-modification".
249 * @param isObsolete
250 * Indicates whether this attribute type is declared
251 * "obsolete".
252 * @param isSingleValue
253 * Indicates whether this attribute type is declared
254 * "single-value".
255 * @param extraProperties
256 * A set of extra properties for this attribute type, or
257 * <code>null</code> if there are no extra properties.
258 */
259 public AttributeType(String definition, String primaryName,
260 Collection<String> typeNames,
261 String oid, String description,
262 AttributeType superiorType,
263 AttributeSyntax syntax,
264 ApproximateMatchingRule
265 approximateMatchingRule,
266 EqualityMatchingRule equalityMatchingRule,
267 OrderingMatchingRule orderingMatchingRule,
268 SubstringMatchingRule substringMatchingRule,
269 AttributeUsage attributeUsage,
270 boolean isCollective,
271 boolean isNoUserModification,
272 boolean isObsolete, boolean isSingleValue,
273 Map<String,List<String>> extraProperties)
274 {
275 super(primaryName, typeNames, oid, description, isObsolete,
276 extraProperties);
277
278
279 ensureNotNull(definition, oid);
280
281 this.superiorType = superiorType;
282 this.isCollective = isCollective;
283 this.isNoUserModification = isNoUserModification;
284 this.isSingleValue = isSingleValue;
285
286 mayHaveSubordinateTypes = false;
287
288 int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME);
289 if (schemaFilePos > 0)
290 {
291 String defStr;
292 try
293 {
294 int firstQuotePos = definition.indexOf('\'', schemaFilePos);
295 int secondQuotePos = definition.indexOf('\'',
296 firstQuotePos+1);
297
298 defStr = definition.substring(0, schemaFilePos).trim() + " " +
299 definition.substring(secondQuotePos+1).trim();
300 }
301 catch (Exception e)
302 {
303 if (debugEnabled())
304 {
305 TRACER.debugCaught(DebugLogLevel.ERROR, e);
306 }
307
308 defStr = definition;
309 }
310
311 this.definition = defStr;
312 }
313 else
314 {
315 this.definition = definition;
316 }
317
318 if (syntax == null)
319 {
320 if (superiorType != null)
321 {
322 this.syntax = superiorType.getSyntax();
323 }
324 else
325 {
326 this.syntax = DirectoryServer.getDefaultAttributeSyntax();
327 }
328 }
329 else
330 {
331 this.syntax = syntax;
332 }
333 syntaxOID = this.syntax.getOID();
334
335
336 if (approximateMatchingRule == null)
337 {
338 this.approximateMatchingRule =
339 this.syntax.getApproximateMatchingRule();
340 }
341 else
342 {
343 this.approximateMatchingRule = approximateMatchingRule;
344 }
345
346
347 if (equalityMatchingRule == null)
348 {
349 this.equalityMatchingRule =
350 this.syntax.getEqualityMatchingRule();
351 }
352 else
353 {
354 this.equalityMatchingRule = equalityMatchingRule;
355 }
356
357
358 if (orderingMatchingRule == null)
359 {
360 this.orderingMatchingRule =
361 this.syntax.getOrderingMatchingRule();
362 }
363 else
364 {
365 this.orderingMatchingRule = orderingMatchingRule;
366 }
367
368
369 if (substringMatchingRule == null)
370 {
371 this.substringMatchingRule =
372 this.syntax.getSubstringMatchingRule();
373 }
374 else
375 {
376 this.substringMatchingRule = substringMatchingRule;
377 }
378
379 if (attributeUsage != null)
380 {
381 this.attributeUsage = attributeUsage;
382 }
383 else
384 {
385 this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
386 }
387
388 if (oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID))
389 {
390 isObjectClassType = true;
391 }
392 else
393 {
394 isObjectClassType = hasName(OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
395 }
396
397 isOperational = this.attributeUsage.isOperational();
398 }
399
400
401
402 /**
403 * Retrieves the definition string used to create this attribute
404 * type.
405 *
406 * @return The definition string used to create this attribute
407 * type.
408 */
409 public String getDefinition()
410 {
411 return definition;
412 }
413
414 /**
415 * Retrieves the definition string used to create this attribute
416 * type and including the X-SCHEMA-FILE extension.
417 *
418 * @return The definition string used to create this attribute
419 * type including the X-SCHEMA-FILE extension.
420 */
421 public String getDefinitionWithFileName()
422 {
423 if (getSchemaFile() != null)
424 {
425 int pos = definition.lastIndexOf(')');
426 String defStr = definition.substring(0, pos).trim() + " " +
427 SCHEMA_PROPERTY_FILENAME + " '" +
428 getSchemaFile() + "' )";
429 return defStr;
430 }
431 else
432 return definition;
433 }
434
435 /**
436 * Creates a new instance of this attribute type based on the
437 * definition string. It will also preserve other state information
438 * associated with this attribute type that is not included in the
439 * definition string (e.g., the name of the schema file with which
440 * it is associated).
441 *
442 * @return The new instance of this attribute type based on the
443 * definition string.
444 *
445 * @throws DirectoryException If a problem occurs while attempting
446 * to create a new attribute type
447 * instance from the definition string.
448 */
449 public AttributeType recreateFromDefinition()
450 throws DirectoryException
451 {
452 ByteString value = ByteStringFactory.create(definition);
453 Schema schema = DirectoryServer.getSchema();
454
455 AttributeType at =
456 AttributeTypeSyntax.decodeAttributeType(value, schema,
457 false);
458 at.setSchemaFile(getSchemaFile());
459 at.mayHaveSubordinateTypes = mayHaveSubordinateTypes;
460
461 return at;
462 }
463
464
465
466 /**
467 * Retrieves the superior type for this attribute type.
468 *
469 * @return The superior type for this attribute type, or
470 * <CODE>null</CODE> if it does not have one.
471 */
472 public AttributeType getSuperiorType()
473 {
474 return superiorType;
475 }
476
477
478
479 /**
480 * Indicates whether there is a possibility that this attribute type
481 * may have one or more subordinate attribute types defined in the
482 * server schema. This is only intended for use by the
483 * {@code org.opends.server.types.Entry} class for the purpose of
484 * determining whether to check for subtypes when retrieving
485 * attributes. Note that it is possible for this method to report
486 * false positives (if an attribute type that previously had one or
487 * more subordinate types no longer has any), but not false
488 * negatives.
489 *
490 * @return {@code true} if the {@code hasSubordinateTypes} flag has
491 * been set for this attribute type at any time since
492 * startup, or {@code false} if not.
493 */
494 boolean mayHaveSubordinateTypes()
495 {
496 return mayHaveSubordinateTypes;
497 }
498
499
500
501 /**
502 * Sets a flag indicating that this attribute type may have one or
503 * more subordinate attribute types defined in the server schema.
504 * This is only intended for use by the
505 * {@code org.opends.server.types.Schema} class.
506 */
507 void setMayHaveSubordinateTypes()
508 {
509 mayHaveSubordinateTypes = true;
510 }
511
512
513
514 /**
515 * Retrieves the syntax for this attribute type.
516 *
517 * @return The syntax for this attribute type.
518 */
519 public AttributeSyntax getSyntax()
520 {
521 return syntax;
522 }
523
524
525
526 /**
527 * Retrieves the OID for this syntax associated with this attribute
528 * type.
529 *
530 * @return The OID for this syntax associated with this attribute
531 * type.
532 */
533 public String getSyntaxOID()
534 {
535 return syntaxOID;
536 }
537
538
539
540 /**
541 * Retrieves the matching rule that should be used for approximate
542 * matching with this attribute type.
543 *
544 * @return The matching rule that should be used for approximate
545 * matching with this attribute type.
546 */
547 public ApproximateMatchingRule getApproximateMatchingRule()
548 {
549 return approximateMatchingRule;
550 }
551
552
553
554 /**
555 * Retrieves the matching rule that should be used for equality
556 * matching with this attribute type.
557 *
558 * @return The matching rule that should be used for equality
559 * matching with this attribute type.
560 */
561 public EqualityMatchingRule getEqualityMatchingRule()
562 {
563 return equalityMatchingRule;
564 }
565
566
567
568 /**
569 * Retrieves the matching rule that should be used for ordering with
570 * this attribute type.
571 *
572 * @return The matching rule that should be used for ordering with
573 * this attribute type.
574 */
575 public OrderingMatchingRule getOrderingMatchingRule()
576 {
577 return orderingMatchingRule;
578 }
579
580
581
582 /**
583 * Retrieves the matching rule that should be used for substring
584 * matching with this attribute type.
585 *
586 * @return The matching rule that should be used for substring
587 * matching with this attribute type.
588 */
589 public SubstringMatchingRule getSubstringMatchingRule()
590 {
591 return substringMatchingRule;
592 }
593
594
595
596 /**
597 * Retrieves the usage indicator for this attribute type.
598 *
599 * @return The usage indicator for this attribute type.
600 */
601 public AttributeUsage getUsage()
602 {
603 return attributeUsage;
604 }
605
606
607
608 /**
609 * Indicates whether this is an operational attribute. An
610 * operational attribute is one with a usage of
611 * "directoryOperation", "distributedOperation", or "dSAOperation"
612 * (i.e., only userApplications is not operational).
613 *
614 * @return <CODE>true</CODE> if this is an operational attribute,
615 * or <CODE>false</CODE> if not.
616 */
617 public boolean isOperational()
618 {
619 return isOperational;
620 }
621
622
623
624 /**
625 * Indicates whether this attribute type is declared "collective".
626 *
627 * @return <CODE>true</CODE> if this attribute type is declared
628 * "collective", or <CODE>false</CODE> if not.
629 */
630 public boolean isCollective()
631 {
632 return isCollective;
633 }
634
635
636
637 /**
638 * Indicates whether this attribute type is declared
639 * "no-user-modification".
640 *
641 * @return <CODE>true</CODE> if this attribute type is declared
642 * "no-user-modification", or <CODE>false</CODE> if not.
643 */
644 public boolean isNoUserModification()
645 {
646 return isNoUserModification;
647 }
648
649
650
651 /**
652 * Indicates whether this attribute type is declared "single-value".
653 *
654 * @return <CODE>true</CODE> if this attribute type is declared
655 * "single-value", or <CODE>false</CODE> if not.
656 */
657 public boolean isSingleValue()
658 {
659 return isSingleValue;
660 }
661
662
663
664 /**
665 * Indicates whether this attribute type represents the
666 * "objectclass" attribute. The determination will be made based on
667 * the name and/or OID.
668 *
669 * @return <CODE>true</CODE> if this attribute type is the
670 * objectclass type, or <CODE>false</CODE> if not.
671 */
672 public boolean isObjectClassType()
673 {
674 return isObjectClassType;
675 }
676
677
678
679 /**
680 * Attempts to normalize the provided value using the equality
681 * matching rule associated with this attribute type.
682 *
683 * @param value The value to be normalized.
684 *
685 * @return The normalized form of the provided value.
686 *
687 * @throws DirectoryException If this attribute type does not have
688 * an equality matching rule, or if the
689 * provided value could not be
690 * normalized.
691 */
692 public ByteString normalize(ByteString value)
693 throws DirectoryException
694 {
695 if (equalityMatchingRule == null)
696 {
697 Message message = ERR_ATTR_TYPE_NORMALIZE_NO_MR.get(
698 String.valueOf(value), getNameOrOID());
699 throw new DirectoryException(ResultCode.INAPPROPRIATE_MATCHING,
700 message);
701 }
702
703 return equalityMatchingRule.normalizeValue(value);
704 }
705
706
707
708 /**
709 * Generates a hash code for the specified attribute value. If an
710 * equality matching rule is defined for this type, then it will be
711 * used to generate the hash code. If the value does not have an
712 * equality matching rule but does have a normalized form, then that
713 * will be used to obtain the hash code. Otherwise, it will simply
714 * be the hash code of the provided value.
715 *
716 * @param value The attribute value for which to generate the hash
717 * code.
718 *
719 * @return The generated hash code for the provided value.
720 */
721 public int generateHashCode(AttributeValue value)
722 {
723 try
724 {
725 if (equalityMatchingRule == null)
726 {
727 ByteString normalizedValue = value.getNormalizedValue();
728 if (normalizedValue == null)
729 {
730 return value.getValue().hashCode();
731 }
732 else
733 {
734 return normalizedValue.hashCode();
735 }
736 }
737 else
738 {
739 return equalityMatchingRule.generateHashCode(value);
740 }
741 }
742 catch (Exception e)
743 {
744 if (debugEnabled())
745 {
746 TRACER.debugCaught(DebugLogLevel.ERROR, e);
747 }
748
749 try
750 {
751 return value.getValue().hashCode();
752 }
753 catch (Exception e2)
754 {
755 if (debugEnabled())
756 {
757 TRACER.debugCaught(DebugLogLevel.ERROR, e2);
758 }
759
760 return 0;
761 }
762 }
763 }
764
765
766
767 /**
768 * Appends a string representation of this schema definition's
769 * non-generic properties to the provided buffer.
770 *
771 * @param buffer The buffer to which the information should be
772 * appended.
773 */
774 protected void toStringContent(StringBuilder buffer)
775 {
776 if (superiorType != null)
777 {
778 buffer.append(" SUP ");
779 buffer.append(superiorType.getNameOrOID());
780 }
781
782 if (equalityMatchingRule != null)
783 {
784 buffer.append(" EQUALITY ");
785 buffer.append(equalityMatchingRule.getNameOrOID());
786 }
787
788 if (orderingMatchingRule != null)
789 {
790 buffer.append(" ORDERING ");
791 buffer.append(orderingMatchingRule.getNameOrOID());
792 }
793
794 if (substringMatchingRule != null)
795 {
796 buffer.append(" SUBSTR ");
797 buffer.append(substringMatchingRule.getNameOrOID());
798 }
799
800 // NOTE -- We will not include any approximate matching rule
801 // information here because it would break the standard and
802 // anything that depends on it.
803 // FIXME -- Should we encode this into one of the "extra"
804 // properties?
805
806 if (syntax != null)
807 {
808 buffer.append(" SYNTAX ");
809 buffer.append(syntax.getOID());
810 }
811
812 if (isSingleValue)
813 {
814 buffer.append(" SINGLE-VALUE");
815 }
816
817 if (isCollective)
818 {
819 buffer.append(" COLLECTIVE");
820 }
821
822 if (isNoUserModification)
823 {
824 buffer.append(" NO-USER-MODIFICATION");
825 }
826
827 if (attributeUsage != null)
828 {
829 buffer.append(" USAGE ");
830 buffer.append(attributeUsage.toString());
831 }
832 }
833 }
834