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.api;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    import java.util.Collection;
034    import java.util.LinkedHashSet;
035    import java.util.List;
036    
037    import org.opends.server.admin.std.server.VirtualAttributeCfg;
038    import org.opends.server.config.ConfigException;
039    import org.opends.server.core.SearchOperation;
040    import org.opends.server.types.AttributeValue;
041    import org.opends.server.types.ByteString;
042    import org.opends.server.types.ConditionResult;
043    import org.opends.server.types.DebugLogLevel;
044    import org.opends.server.types.Entry;
045    import org.opends.server.types.InitializationException;
046    import org.opends.server.types.VirtualAttributeRule;
047    
048    import static org.opends.server.loggers.debug.DebugLogger.*;
049    import org.opends.server.loggers.debug.DebugTracer;
050    
051    
052    
053    /**
054     * This class defines the set of methods and structures that must be
055     * implemented by a Directory Server module that implements the
056     * functionality required for one or more virtual attributes.
057     *
058     * @param  <T>  The type of configuration handled by this virtual
059     *              attribute provider.
060     */
061    @org.opends.server.types.PublicAPI(
062         stability=org.opends.server.types.StabilityLevel.VOLATILE,
063         mayInstantiate=false,
064         mayExtend=true,
065         mayInvoke=false)
066    public abstract class VirtualAttributeProvider
067           <T extends VirtualAttributeCfg>
068    {
069      /**
070       * The tracer object for the debug logger.
071       */
072      private static final DebugTracer TRACER = getTracer();
073    
074      /**
075       * Initializes this virtual attribute based on the information in
076       * the provided configuration entry.
077       *
078       * @param  configuration  The configuration to use to initialize
079       *                        this virtual attribute provider.
080       *
081       * @throws  ConfigException  If an unrecoverable problem arises in
082       *                           the process of performing the
083       *                           initialization.
084       *
085       * @throws  InitializationException  If a problem occurs during
086       *                                   initialization that is not
087       *                                   related to the server
088       *                                   configuration.
089       */
090      public abstract void initializeVirtualAttributeProvider(
091                                T configuration)
092             throws ConfigException, InitializationException;
093    
094    
095    
096      /**
097       * Indicates whether the provided configuration is acceptable for
098       * this virtual attribute provider.  It should be possible to call
099       * this method on an uninitialized virtual attribute provider
100       * instance in order to determine whether the virtual attribute
101       * provider would be able to use the provided configuration.
102       *
103       * @param  configuration        The virtual attribute provider
104       *                              configuration for which to make the
105       *                              determination.
106       * @param  unacceptableReasons  A list that may be used to hold the
107       *                              reasons that the provided
108       *                              configuration is not acceptable.
109       *
110       * @return  {@code true} if the provided configuration is acceptable
111       *          for this virtual attribute provider, or {@code false} if
112       *          not.
113       */
114      public boolean isConfigurationAcceptable(
115                          VirtualAttributeCfg configuration,
116                          List<Message> unacceptableReasons)
117      {
118        // This default implementation does not perform any special
119        // validation.  It should be overridden by virtual attribute
120        // provider implementations that wish to perform more detailed
121        // validation.
122        return true;
123      }
124    
125    
126    
127      /**
128       * Performs any finalization that may be necessary whenever this
129       * virtual attribute provider is taken out of service.
130       */
131      public void finalizeVirtualAttributeProvider()
132      {
133        // No implementation required by default.
134      }
135    
136    
137    
138      /**
139       * Indicates whether this virtual attribute provider may generate
140       * multiple values.
141       *
142       * @return  {@code true} if this virtual attribute provider may
143       *          generate multiple values, or {@code false} if not.
144       */
145      public abstract boolean isMultiValued();
146    
147    
148    
149      /**
150       * Generates a set of values for the provided entry.
151       *
152       * @param  entry  The entry for which the values are to be
153       *                generated.
154       * @param  rule   The virtual attribute rule which defines the
155       *                constraints for the virtual attribute.
156       *
157       * @return  The set of values generated for the provided entry.  It
158       *          may be empty, but it must not be {@code null}.
159       */
160      public abstract LinkedHashSet<AttributeValue>
161                           getValues(Entry entry,
162                                     VirtualAttributeRule rule);
163    
164    
165    
166      /**
167       * Indicates whether this virtual attribute provider will generate
168       * at least one value for the provided entry.
169       *
170       * @param  entry  The entry for which to make the determination.
171       * @param  rule   The virtual attribute rule which defines the
172       *                constraints for the virtual attribute.
173       *
174       * @return  {@code true} if this virtual attribute provider will
175       *          generate at least one value for the provided entry, or
176       *          {@code false} if not.
177       */
178      public boolean hasValue(Entry entry, VirtualAttributeRule rule)
179      {
180        return (! getValues(entry, rule).isEmpty());
181      }
182    
183    
184    
185      /**
186       * Indicates whether this virtual attribute provider will generate
187       * the provided value.
188       *
189       * @param  entry  The entry for which to make the determination.
190       * @param  rule   The virtual attribute rule which defines the
191       *                constraints for the virtual attribute.
192       * @param  value  The value for which to make the determination.
193       *
194       * @return  {@code true} if this virtual attribute provider will
195       *          generate the specified vaule for the provided entry, or
196       *          {@code false} if not.
197       */
198      public boolean hasValue(Entry entry, VirtualAttributeRule rule,
199                              AttributeValue value)
200      {
201        return getValues(entry, rule).contains(value);
202      }
203    
204    
205    
206      /**
207       * Indicates whether this virtual attribute provider will generate
208       * all of the values in the provided collection.
209       *
210       * @param  entry   The entry for which to make the determination.
211       * @param  rule    The virtual attribute rule which defines the
212       *                 constraints for the virtual attribute.
213       * @param  values  The set of values for which to make the
214       *                 determination.
215       *
216       * @return  {@code true} if this attribute provider will generate
217       *          all of the values in the provided collection, or
218       *          {@code false} if it will not generate at least one of
219       *          them.
220       */
221      public boolean hasAllValues(Entry entry, VirtualAttributeRule rule,
222                                  Collection<AttributeValue> values)
223      {
224        for (AttributeValue value : values)
225        {
226          if (! getValues(entry, rule).contains(value))
227          {
228            return false;
229          }
230        }
231    
232        return true;
233      }
234    
235    
236    
237      /**
238       * Indicates whether this virutal attribute provider will generate
239       * any of the values in the provided collection.
240       *
241       * @param  entry   The entry for which to make the determination.
242       * @param  rule    The virtual attribute rule which defines the
243       *                 constraints for the virtual attribute.
244       * @param  values  The set of values for which to make the
245       *                 determination.
246       *
247       * @return  {@code true} if this attribute provider will generate
248       *          at least one of the values in the provided collection,
249       *          or {@code false} if it will not generate any of them.
250       */
251      public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule,
252                                 Collection<AttributeValue> values)
253      {
254        for (AttributeValue value : values)
255        {
256          if (getValues(entry, rule).contains(value))
257          {
258            return true;
259          }
260        }
261    
262        return false;
263      }
264    
265    
266    
267      /**
268       * Indicates whether this virtual attribute provider will generate
269       * any value which matches the provided substring.
270       *
271       * @param  entry       The entry for which to make the
272       *                     determination.
273       * @param  rule        The virtual attribute rule which defines the
274       *                     constraints for the virtual attribute.
275       * @param  subInitial  The subInitial component to use in the
276       *                     determination.
277       * @param  subAny      The subAny components to use in the
278       *                     determination.
279       * @param  subFinal    The subFinal component to use in the
280       *                     determination.
281       *
282       * @return  {@code UNDEFINED} if this attribute does not have a
283       *          substring matching rule, {@code TRUE} if at least one
284       *          value matches the provided substring, or {@code FALSE}
285       *          otherwise.
286       */
287      public ConditionResult matchesSubstring(Entry entry,
288                                              VirtualAttributeRule rule,
289                                              ByteString subInitial,
290                                              List<ByteString> subAny,
291                                              ByteString subFinal)
292      {
293        SubstringMatchingRule matchingRule =
294             rule.getAttributeType().getSubstringMatchingRule();
295        if (matchingRule == null)
296        {
297          return ConditionResult.UNDEFINED;
298        }
299    
300    
301        ByteString normalizedSubInitial;
302        if (subInitial == null)
303        {
304          normalizedSubInitial = null;
305        }
306        else
307        {
308          try
309          {
310            normalizedSubInitial =
311                 matchingRule.normalizeSubstring(subInitial);
312          }
313          catch (Exception e)
314          {
315            if (debugEnabled())
316            {
317              TRACER.debugCaught(DebugLogLevel.ERROR, e);
318            }
319    
320            // The substring couldn't be normalized.  We have to return
321            // "undefined".
322            return ConditionResult.UNDEFINED;
323          }
324        }
325    
326    
327        ArrayList<ByteString> normalizedSubAny;
328        if (subAny == null)
329        {
330          normalizedSubAny = null;
331        }
332        else
333        {
334          normalizedSubAny =
335               new ArrayList<ByteString>(subAny.size());
336          for (ByteString subAnyElement : subAny)
337          {
338            try
339            {
340              normalizedSubAny.add(matchingRule.normalizeSubstring(
341                                                     subAnyElement));
342            }
343            catch (Exception e)
344            {
345              if (debugEnabled())
346              {
347                TRACER.debugCaught(DebugLogLevel.ERROR, e);
348              }
349    
350              // The substring couldn't be normalized.  We have to return
351              // "undefined".
352              return ConditionResult.UNDEFINED;
353            }
354          }
355        }
356    
357    
358        ByteString normalizedSubFinal;
359        if (subFinal == null)
360        {
361          normalizedSubFinal = null;
362        }
363        else
364        {
365          try
366          {
367            normalizedSubFinal =
368                 matchingRule.normalizeSubstring(subFinal);
369          }
370          catch (Exception e)
371          {
372            if (debugEnabled())
373            {
374              TRACER.debugCaught(DebugLogLevel.ERROR, e);
375            }
376    
377            // The substring couldn't be normalized.  We have to return
378            // "undefined".
379            return ConditionResult.UNDEFINED;
380          }
381        }
382    
383    
384        ConditionResult result = ConditionResult.FALSE;
385        for (AttributeValue value : getValues(entry, rule))
386        {
387          try
388          {
389            if (matchingRule.valueMatchesSubstring(
390                                  value.getNormalizedValue(),
391                                  normalizedSubInitial,
392                                  normalizedSubAny,
393                                  normalizedSubFinal))
394            {
395              return ConditionResult.TRUE;
396            }
397          }
398          catch (Exception e)
399          {
400            if (debugEnabled())
401            {
402              TRACER.debugCaught(DebugLogLevel.ERROR, e);
403            }
404    
405            // The value couldn't be normalized.  If we can't find a
406            // definite match, then we should return "undefined".
407            result = ConditionResult.UNDEFINED;
408          }
409        }
410    
411        return result;
412      }
413    
414    
415    
416      /**
417       * Indicates whether this virtual attribute provider will generate
418       * any value for the provided entry that is greater than or equal to
419       * the given value.
420       *
421       * @param  entry  The entry for which to make the determination.
422       * @param  rule   The virtual attribute rule which defines the
423       *                constraints for the virtual attribute.
424       * @param  value  The value for which to make the determination.
425       *
426       * @return  {@code UNDEFINED} if the associated attribute type does
427       *          not have an ordering matching rule, {@code TRUE} if at
428       *          least one of the generated values will be greater than
429       *          or equal to the specified value, or {@code FALSE} if
430       *          none of the generated values will be greater than or
431       *          equal to the specified value.
432       */
433      public ConditionResult greaterThanOrEqualTo(Entry entry,
434                                  VirtualAttributeRule rule,
435                                  AttributeValue value)
436      {
437        OrderingMatchingRule matchingRule =
438             rule.getAttributeType().getOrderingMatchingRule();
439        if (matchingRule == null)
440        {
441          return ConditionResult.UNDEFINED;
442        }
443    
444        ByteString normalizedValue;
445        try
446        {
447          normalizedValue = value.getNormalizedValue();
448        }
449        catch (Exception e)
450        {
451          if (debugEnabled())
452          {
453            TRACER.debugCaught(DebugLogLevel.ERROR, e);
454          }
455    
456          // We couldn't normalize the provided value.  We should return
457          // "undefined".
458          return ConditionResult.UNDEFINED;
459        }
460    
461        ConditionResult result = ConditionResult.FALSE;
462        for (AttributeValue v : getValues(entry, rule))
463        {
464          try
465          {
466            ByteString nv = v.getNormalizedValue();
467            int comparisonResult =
468                     matchingRule.compareValues(nv, normalizedValue);
469            if (comparisonResult >= 0)
470            {
471              return ConditionResult.TRUE;
472            }
473          }
474          catch (Exception e)
475          {
476            if (debugEnabled())
477            {
478              TRACER.debugCaught(DebugLogLevel.ERROR, e);
479            }
480    
481            // We couldn't normalize one of the attribute values.  If we
482            // can't find a definite match, then we should return
483            // "undefined".
484            result = ConditionResult.UNDEFINED;
485          }
486        }
487    
488        return result;
489      }
490    
491    
492    
493      /**
494       * Indicates whether this virtual attribute provider will generate
495       * any value for the provided entry that is less than or equal to
496       * the given value.
497       *
498       * @param  entry  The entry for which to make the determination.
499       * @param  rule   The virtual attribute rule which defines the
500       *                constraints for the virtual attribute.
501       * @param  value  The value for which to make the determination.
502       *
503       * @return  {@code UNDEFINED} if the associated attribute type does
504       *          not have an ordering matching rule, {@code TRUE} if at
505       *          least one of the generated values will be less than or
506       *          equal to the specified value, or {@code FALSE} if none
507       *          of the generated values will be greater than or equal to
508       *          the specified value.
509       */
510      public ConditionResult lessThanOrEqualTo(Entry entry,
511                                  VirtualAttributeRule rule,
512                                  AttributeValue value)
513      {
514        OrderingMatchingRule matchingRule =
515             rule.getAttributeType().getOrderingMatchingRule();
516        if (matchingRule == null)
517        {
518          return ConditionResult.UNDEFINED;
519        }
520    
521        ByteString normalizedValue;
522        try
523        {
524          normalizedValue = value.getNormalizedValue();
525        }
526        catch (Exception e)
527        {
528          if (debugEnabled())
529          {
530            TRACER.debugCaught(DebugLogLevel.ERROR, e);
531          }
532    
533          // We couldn't normalize the provided value.  We should return
534          // "undefined".
535          return ConditionResult.UNDEFINED;
536        }
537    
538        ConditionResult result = ConditionResult.FALSE;
539        for (AttributeValue v : getValues(entry, rule))
540        {
541          try
542          {
543            ByteString nv = v.getNormalizedValue();
544            int comparisonResult =
545                     matchingRule.compareValues(nv, normalizedValue);
546            if (comparisonResult <= 0)
547            {
548              return ConditionResult.TRUE;
549            }
550          }
551          catch (Exception e)
552          {
553            if (debugEnabled())
554            {
555              TRACER.debugCaught(DebugLogLevel.ERROR, e);
556            }
557    
558            // We couldn't normalize one of the attribute values.  If we
559            // can't find a definite match, then we should return
560            // "undefined".
561            result = ConditionResult.UNDEFINED;
562          }
563        }
564    
565        return result;
566      }
567    
568    
569    
570      /**
571       * Indicates whether this virtual attribute provider will generate
572       * any value for the provided entry that is approximately equal to
573       * the given value.
574       *
575       * @param  entry  The entry for which to make the determination.
576       * @param  rule   The virtual attribute rule which defines the
577       *                constraints for the virtual attribute.
578       * @param  value  The value for which to make the determination.
579       *
580       * @return  {@code UNDEFINED} if the associated attribute type does
581       *          not have an aproximate matching rule, {@code TRUE} if at
582       *          least one of the generated values will be approximately
583       *          equal to the specified value, or {@code FALSE} if none
584       *          of the generated values will be approximately equal to
585       *          the specified value.
586       */
587      public ConditionResult approximatelyEqualTo(Entry entry,
588                                  VirtualAttributeRule rule,
589                                  AttributeValue value)
590      {
591        ApproximateMatchingRule matchingRule =
592             rule.getAttributeType().getApproximateMatchingRule();
593        if (matchingRule == null)
594        {
595          return ConditionResult.UNDEFINED;
596        }
597    
598        ByteString normalizedValue;
599        try
600        {
601          normalizedValue = matchingRule.normalizeValue(value.getValue());
602        }
603        catch (Exception e)
604        {
605          if (debugEnabled())
606          {
607            TRACER.debugCaught(DebugLogLevel.ERROR, e);
608          }
609    
610          // We couldn't normalize the provided value.  We should return
611          // "undefined".
612          return ConditionResult.UNDEFINED;
613        }
614    
615        ConditionResult result = ConditionResult.FALSE;
616        for (AttributeValue v : getValues(entry, rule))
617        {
618          try
619          {
620            ByteString nv = matchingRule.normalizeValue(v.getValue());
621            if (matchingRule.approximatelyMatch(nv, normalizedValue))
622            {
623              return ConditionResult.TRUE;
624            }
625          }
626          catch (Exception e)
627          {
628            if (debugEnabled())
629            {
630              TRACER.debugCaught(DebugLogLevel.ERROR, e);
631            }
632    
633            // We couldn't normalize one of the attribute values.  If we
634            // can't find a definite match, then we should return
635            // "undefined".
636            result = ConditionResult.UNDEFINED;
637          }
638        }
639    
640        return result;
641      }
642    
643    
644    
645      /**
646       * Indicates whether this attribute may be included in search
647       * filters as part of the criteria for locating entries.
648       *
649       * @param  rule             The virtual attribute rule which defines
650       *                          the constraints for the virtual
651       *                          attribute.
652       * @param  searchOperation  The search operation for which to make
653       *                          the determination.
654       *
655       * @return  {@code true} if this attribute may be included in search
656       *          filters, or {@code false} if not.
657       */
658      public abstract boolean isSearchable(VirtualAttributeRule rule,
659                                           SearchOperation
660                                                searchOperation);
661    
662    
663    
664      /**
665       * Processes the provided search operation in which the search
666       * criteria includes an operation targeted at this virtual
667       * attribute.  This method should only be called if
668       * {@code isSearchable} returns true and it is not possible to
669       * construct a manageable candidate list by processing other
670       * elements of the search criteria.
671       *
672       * @param  rule             The virtual attribute rule which defines
673       *                          the constraints for the virtual
674       *                          attribute.
675       * @param  searchOperation  The search operation to be processed.
676       */
677      public abstract void processSearch(VirtualAttributeRule rule,
678                                         SearchOperation searchOperation);
679    }
680