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