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
029
030
031 import java.util.Iterator;
032 import java.util.LinkedHashMap;
033 import java.util.LinkedHashSet;
034 import java.util.LinkedList;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Set;
038
039 import org.opends.server.schema.DITStructureRuleSyntax;
040
041 import static org.opends.server.loggers.debug.DebugLogger.*;
042 import org.opends.server.loggers.debug.DebugTracer;
043 import static org.opends.server.util.ServerConstants.*;
044 import static org.opends.server.util.Validator.*;
045
046
047
048 /**
049 * This class defines a DIT structure rule, which is used to indicate
050 * the types of children that entries may have.
051 */
052 @org.opends.server.types.PublicAPI(
053 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
054 mayInstantiate=false,
055 mayExtend=false,
056 mayInvoke=true)
057 public final class DITStructureRule
058 implements SchemaFileElement
059 {
060 /**
061 * The tracer object for the debug logger.
062 */
063 private static final DebugTracer TRACER = getTracer();
064
065 // Indicates whether this DIT structure rule is declared "obsolete".
066 private final boolean isObsolete;
067
068 // The rule ID for this DIT structure rule.
069 private final int ruleID;
070
071 // The name form for this DIT structure rule.
072 private final NameForm nameForm;
073
074 // The set of additional name-value pairs associated with this DIT
075 // structure rule.
076 private final Map<String,List<String>> extraProperties;
077
078 // The set of names for this DIT structure rule, in a mapping
079 // between the all-lowercase form and the user-defined form.
080 private final Map<String,String> names;
081
082 // The set of superior DIT structure rules.
083 private final Set<DITStructureRule> superiorRules;
084
085 // The definition string for this DIT structure rule.
086 private final String definition;
087
088 // The description for this DIT structure rule.
089 private final String description;
090
091
092
093 /**
094 * Creates a new DIT structure rule with the provided information.
095 *
096 * @param definition The definition string used to create
097 * this DIT structure rule. It must not be
098 * {@code null}.
099 * @param names The set of names for this DIT structure
100 * rule, mapping the lowercase names to the
101 * user-defined values.
102 * @param ruleID The rule ID for this DIT structure rule.
103 * @param description The description for this DIT structure
104 * rule.
105 * @param isObsolete Indicates whether this DIT structure
106 * rule is declared "obsolete".
107 * @param nameForm The name form for this DIT structure
108 * rule.
109 * @param superiorRules References to the superior rules for
110 * this DIT structure rule.
111 * @param extraProperties The set of "extra" properties associated
112 * with this DIT structure rules.
113 */
114 public DITStructureRule(String definition, Map<String,String> names,
115 int ruleID, String description,
116 boolean isObsolete, NameForm nameForm,
117 Set<DITStructureRule> superiorRules,
118 Map<String,List<String>> extraProperties)
119 {
120 ensureNotNull(definition);
121
122 this.ruleID = ruleID;
123 this.description = description;
124 this.isObsolete = isObsolete;
125 this.nameForm = nameForm;
126
127 int schemaFilePos = definition.indexOf(SCHEMA_PROPERTY_FILENAME);
128 if (schemaFilePos > 0)
129 {
130 String defStr;
131 try
132 {
133 int firstQuotePos = definition.indexOf('\'', schemaFilePos);
134 int secondQuotePos = definition.indexOf('\'',
135 firstQuotePos+1);
136
137 defStr = definition.substring(0, schemaFilePos).trim() + " " +
138 definition.substring(secondQuotePos+1).trim();
139 }
140 catch (Exception e)
141 {
142 if (debugEnabled())
143 {
144 TRACER.debugCaught(DebugLogLevel.ERROR, e);
145 }
146
147 defStr = definition;
148 }
149
150 this.definition = defStr;
151 }
152 else
153 {
154 this.definition = definition;
155 }
156
157 if ((names == null) || names.isEmpty())
158 {
159 this.names = new LinkedHashMap<String,String>(0);
160 }
161 else
162 {
163 this.names = new LinkedHashMap<String,String>(names);
164 }
165
166 if ((superiorRules == null) || superiorRules.isEmpty())
167 {
168 this.superiorRules = new LinkedHashSet<DITStructureRule>(0);
169 }
170 else
171 {
172 this.superiorRules =
173 new LinkedHashSet<DITStructureRule>(superiorRules);
174 }
175
176 if ((extraProperties == null) || extraProperties.isEmpty())
177 {
178 this.extraProperties =
179 new LinkedHashMap<String,List<String>>(0);
180 }
181 else
182 {
183 this.extraProperties =
184 new LinkedHashMap<String,List<String>>(extraProperties);
185 }
186 }
187
188
189
190 /**
191 * Retrieves the definition string used to create this DIT structure
192 * rule.
193 *
194 * @return The definition string used to create this DIT structure
195 * rule.
196 */
197 public String getDefinition()
198 {
199 return definition;
200 }
201
202
203
204 /**
205 * Creates a new instance of this DIT structure rule based on the
206 * definition string. It will also preserve other state information
207 * associated with this DIT structure rule that is not included in
208 * the definition string (e.g., the name of the schema file with
209 * which it is associated).
210 *
211 * @return The new instance of this DIT structure rule based on the
212 * definition string.
213 *
214 * @throws DirectoryException If a problem occurs while attempting
215 * to create a new DIT structure rule
216 * instance from the definition string.
217 */
218 public DITStructureRule recreateFromDefinition()
219 throws DirectoryException
220 {
221 ByteString value = ByteStringFactory.create(definition);
222 Schema schema = DirectoryConfig.getSchema();
223
224 DITStructureRule dsr =
225 DITStructureRuleSyntax.decodeDITStructureRule(value, schema,
226 false);
227 dsr.setSchemaFile(getSchemaFile());
228
229 return dsr;
230 }
231
232
233
234 /**
235 * Retrieves the set of names that may be used to reference this DIT
236 * structure rule. The returned mapping will be between an all
237 * lower-case form of the name and a name in the user-defined form
238 * (which may include mixed capitalization).
239 *
240 * @return The set of names that may be used to reference this DIT
241 * structure rule.
242 */
243 public Map<String,String> getNames()
244 {
245 return names;
246 }
247
248
249
250 /**
251 * Indicates whether this DIT structure rule has the specified name.
252 *
253 * @param lowerName The lowercase name for which to make the
254 * determination.
255 *
256 * @return {@code true} if the specified name is assigned to this
257 * DIT structure rule, or {@code false} if not.
258 */
259 public boolean hasName(String lowerName)
260 {
261 return names.containsKey(lowerName);
262 }
263
264
265
266 /**
267 * Retrieves the rule ID for this DIT structure rule.
268 *
269 * @return The rule ID for this DIT structure rule.
270 */
271 public int getRuleID()
272 {
273 return ruleID;
274 }
275
276
277
278 /**
279 * Retrieves the name or rule ID for this DIT structure rule. If it
280 * has one or more names, then the primary name will be returned.
281 * If it does not have any names, then the rule ID will be returned.
282 *
283 * @return The name or rule ID for this DIT structure rule.
284 */
285 public String getNameOrRuleID()
286 {
287 if (names.isEmpty())
288 {
289 return String.valueOf(ruleID);
290 }
291 else
292 {
293 return names.values().iterator().next();
294 }
295 }
296
297
298
299 /**
300 * Retrieves the path to the schema file that contains the
301 * definition for this DIT structure rule.
302 *
303 * @return The path to the schema file that contains the definition
304 * for this DIT structure rule, or {@code null} if it
305 * is not known or if it is not stored in any schema file.
306 */
307 public String getSchemaFile()
308 {
309 List<String> values =
310 extraProperties.get(SCHEMA_PROPERTY_FILENAME);
311 if ((values == null) || values.isEmpty())
312 {
313 return null;
314 }
315
316 return values.get(0);
317 }
318
319
320
321 /**
322 * Specifies the path to the schema file that contains the
323 * definition for this DIT structure rule.
324 *
325 * @param schemaFile The path to the schema file that contains the
326 * definition for this DIT structure rule.
327 */
328 public void setSchemaFile(String schemaFile)
329 {
330 setExtraProperty(SCHEMA_PROPERTY_FILENAME, schemaFile);
331 }
332
333
334
335 /**
336 * Retrieves the description for this DIT structure rule.
337 *
338 * @return The description for this DIT structure rule.
339 */
340 public String getDescription()
341 {
342 return description;
343 }
344
345
346
347 /**
348 * Retrieves the name form for this DIT structure rule.
349 *
350 * @return The name form for this DIT structure rule.
351 */
352 public NameForm getNameForm()
353 {
354 return nameForm;
355 }
356
357
358
359 /**
360 * Retrieves the structural objectclass for the name form with which
361 * this DIT structure rule is associated.
362 *
363 * @return The structural objectclass for the name form with which
364 * this DIT structure rule is associated.
365 */
366 public ObjectClass getStructuralClass()
367 {
368 return nameForm.getStructuralClass();
369 }
370
371
372
373 /**
374 * Retrieves the set of superior rules for this DIT structure rule.
375 *
376 * @return The set of superior rules for this DIT structure rule.
377 */
378 public Set<DITStructureRule> getSuperiorRules()
379 {
380 return superiorRules;
381 }
382
383
384
385 /**
386 * Indicates whether this DIT structure rule has one or more
387 * superior rules.
388 *
389 * @return {@code true} if this DIT structure rule has one or more
390 * superior rules, or {@code false} if not.
391 */
392 public boolean hasSuperiorRules()
393 {
394 return ((superiorRules != null) && (! superiorRules.isEmpty()));
395 }
396
397
398
399 /**
400 * Indicates whether this DIT structure rule is declared "obsolete".
401 *
402 * @return {@code true} if this DIT structure rule is declared
403 * "obsolete", or {@code false} if not.
404 */
405 public boolean isObsolete()
406 {
407 return isObsolete;
408 }
409
410
411
412 /**
413 * Retrieves a mapping between the names of any extra non-standard
414 * properties that may be associated with this DIT structure rule
415 * and the value for that property.
416 *
417 * @return A mapping between the names of any extra non-standard
418 * properties that may be associated with this DIT
419 * structure rule and the value for that property.
420 */
421 public Map<String,List<String>> getExtraProperties()
422 {
423 return extraProperties;
424 }
425
426
427
428 /**
429 * Retrieves the value of the specified "extra" property for this
430 * DIT structure rule.
431 *
432 * @param propertyName The name of the "extra" property for which
433 * to retrieve the value.
434 *
435 * @return The value of the specified "extra" property for this DIT
436 * structure rule, or {@code null} if no such property is
437 * defined.
438 */
439 public List<String> getExtraProperty(String propertyName)
440 {
441 return extraProperties.get(propertyName);
442 }
443
444
445
446 /**
447 * Specifies the provided "extra" property for this DIT structure
448 * rule.
449 *
450 * @param name The name for the "extra" property. It must not be
451 * {@code null}.
452 * @param value The value for the "extra" property, or
453 * {@code null} if the property is to be removed.
454 */
455 public void setExtraProperty(String name, String value)
456 {
457 ensureNotNull(name);
458
459 if (value == null)
460 {
461 extraProperties.remove(name);
462 }
463 else
464 {
465 LinkedList<String> values = new LinkedList<String>();
466 values.add(value);
467
468 extraProperties.put(name, values);
469 }
470 }
471
472
473
474 /**
475 * Specifies the provided "extra" property for this DIT structure
476 * rule.
477 *
478 * @param name The name for the "extra" property. It must not
479 * be {@code null}.
480 * @param values The set of value for the "extra" property, or
481 * {@code null} if the property is to be removed.
482 */
483 public void setExtraProperty(String name, List<String> values)
484 {
485 ensureNotNull(name);
486
487 if ((values == null) || values.isEmpty())
488 {
489 extraProperties.remove(name);
490 }
491 else
492 {
493 LinkedList<String> valuesCopy = new LinkedList<String>(values);
494 extraProperties.put(name, valuesCopy);
495 }
496 }
497
498
499
500 /**
501 * Indicates whether the provided object is equal to this DIT
502 * structure rule. The object will be considered equal if it is a
503 * DIT structure rule with the same OID as the current type.
504 *
505 * @param o The object for which to make the determination.
506 *
507 * @return {@code true} if the provided object is equal to this
508 * attribute, or {@code false} if not.
509 */
510 public boolean equals(Object o)
511 {
512 if (this == o)
513 {
514 return true;
515 }
516
517 if ((o == null) || (! (o instanceof DITStructureRule)))
518 {
519 return false;
520 }
521
522 return (ruleID == ((DITStructureRule) o).ruleID);
523 }
524
525
526
527 /**
528 * Retrieves the hash code for this DIT structure rule. It will be
529 * equal to the rule ID.
530 *
531 * @return The hash code for this DIT structure rule.
532 */
533 public int hashCode()
534 {
535 return ruleID;
536 }
537
538
539
540 /**
541 * Retrieves the string representation of this attribute type in the
542 * form specified in RFC 2252.
543 *
544 * @return The string representation of this attribute type in the
545 * form specified in RFC 2252.
546 */
547 public String toString()
548 {
549 StringBuilder buffer = new StringBuilder();
550 toString(buffer, true);
551 return buffer.toString();
552 }
553
554
555
556 /**
557 * Appends a string representation of this attribute type in the
558 * form specified in RFC 2252 to the provided buffer.
559 *
560 * @param buffer The buffer to which the information
561 * should be appended.
562 * @param includeFileElement Indicates whether to include an
563 * "extra" property that specifies the
564 * path to the schema file from which
565 * this DIT structure rule was loaded.
566 */
567 public void toString(StringBuilder buffer,
568 boolean includeFileElement)
569 {
570 buffer.append("( ");
571 buffer.append(ruleID);
572
573 if (! names.isEmpty())
574 {
575 Iterator<String> iterator = names.values().iterator();
576
577 String firstName = iterator.next();
578 if (iterator.hasNext())
579 {
580 buffer.append(" NAME ( '");
581 buffer.append(firstName);
582
583 while (iterator.hasNext())
584 {
585 buffer.append("' '");
586 buffer.append(iterator.next());
587 }
588
589 buffer.append("' )");
590 }
591 else
592 {
593 buffer.append(" NAME '");
594 buffer.append(firstName);
595 buffer.append("'");
596 }
597 }
598
599 if ((description != null) && (description.length() > 0))
600 {
601 buffer.append(" DESC '");
602 buffer.append(description);
603 buffer.append("'");
604 }
605
606 if (isObsolete)
607 {
608 buffer.append(" OBSOLETE");
609 }
610
611 buffer.append(" FORM ");
612 buffer.append(nameForm.getNameOrOID());
613
614 if ((superiorRules != null) && (! superiorRules.isEmpty()))
615 {
616 Iterator<DITStructureRule> iterator = superiorRules.iterator();
617
618 int firstRule = iterator.next().getRuleID();
619 if (iterator.hasNext())
620 {
621 buffer.append(" SUP ( ");
622 buffer.append(firstRule);
623
624 while (iterator.hasNext())
625 {
626 buffer.append(" ");
627 buffer.append(iterator.next().getRuleID());
628 }
629
630 buffer.append(" )");
631 }
632 else
633 {
634 buffer.append(" SUP ");
635 buffer.append(firstRule);
636 }
637 }
638
639 if (! extraProperties.isEmpty())
640 {
641 for (String property : extraProperties.keySet())
642 {
643 if ((! includeFileElement) &&
644 property.equals(SCHEMA_PROPERTY_FILENAME))
645 {
646 continue;
647 }
648
649 List<String> valueList = extraProperties.get(property);
650
651 buffer.append(" ");
652 buffer.append(property);
653
654 if (valueList.size() == 1)
655 {
656 buffer.append(" '");
657 buffer.append(valueList.get(0));
658 buffer.append("'");
659 }
660 else
661 {
662 buffer.append(" ( ");
663
664 for (String value : valueList)
665 {
666 buffer.append("'");
667 buffer.append(value);
668 buffer.append("' ");
669 }
670
671 buffer.append(")");
672 }
673 }
674 }
675
676 buffer.append(" )");
677 }
678 }
679