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.schema;
028    
029    
030    
031    import org.opends.server.admin.std.server.EqualityMatchingRuleCfg;
032    import org.opends.server.api.EqualityMatchingRule;
033    import org.opends.server.config.ConfigException;
034    import org.opends.server.protocols.asn1.ASN1OctetString;
035    import org.opends.server.types.AttributeValue;
036    import org.opends.server.types.ByteString;
037    import org.opends.server.types.DirectoryException;
038    import org.opends.server.types.InitializationException;
039    
040    import static org.opends.server.schema.SchemaConstants.*;
041    import static org.opends.server.util.StaticUtils.*;
042    
043    
044    
045    /**
046     * This class implements the wordMatch matching rule defined in X.520.  That
047     * document defines "word" as implementation-specific, but in this case we will
048     * consider it a match if the assertion value is contained within the attribute
049     * value and is bounded by the edge of the value or any of the following
050     * characters:
051     * <BR>
052     * <UL>
053     *   <LI>A space</LI>
054     *   <LI>A period</LI>
055     *   <LI>A comma</LI>
056     *   <LI>A slash</LI>
057     *   <LI>A dollar sign</LI>
058     *   <LI>A plus sign</LI>
059     *   <LI>A dash</LI>
060     *   <LI>An underscore</LI>
061     *   <LI>An octothorpe</LI>
062     *   <LI>An equal sign</LI>
063     * </UL>
064     */
065    public class WordEqualityMatchingRule
066           extends EqualityMatchingRule
067    {
068      /**
069       * Creates a new instance of this wordMatch matching rule.
070       */
071      public WordEqualityMatchingRule()
072      {
073        super();
074      }
075    
076    
077    
078      /**
079       * {@inheritDoc}
080       */
081      public void initializeMatchingRule(EqualityMatchingRuleCfg configuration)
082             throws ConfigException, InitializationException
083      {
084        // No initialization is required.
085      }
086    
087    
088    
089      /**
090       * Retrieves the common name for this matching rule.
091       *
092       * @return  The common name for this matching rule, or <CODE>null</CODE> if
093       * it does not have a name.
094       */
095      public String getName()
096      {
097        return EMR_WORD_NAME;
098      }
099    
100    
101    
102      /**
103       * Retrieves the OID for this matching rule.
104       *
105       * @return  The OID for this matching rule.
106       */
107      public String getOID()
108      {
109        return EMR_WORD_OID;
110      }
111    
112    
113    
114      /**
115       * Retrieves the description for this matching rule.
116       *
117       * @return  The description for this matching rule, or <CODE>null</CODE> if
118       *          there is none.
119       */
120      public String getDescription()
121      {
122        // There is no standard description for this matching rule.
123        return null;
124      }
125    
126    
127    
128      /**
129       * Retrieves the OID of the syntax with which this matching rule is
130       * associated.
131       *
132       * @return  The OID of the syntax with which this matching rule is associated.
133       */
134      public String getSyntaxOID()
135      {
136        return SYNTAX_DIRECTORY_STRING_OID;
137      }
138    
139    
140    
141      /**
142       * Retrieves the normalized form of the provided value, which is best suited
143       * for efficiently performing matching operations on that value.
144       *
145       * @param  value  The value to be normalized.
146       *
147       * @return  The normalized version of the provided value.
148       *
149       * @throws  DirectoryException  If the provided value is invalid according to
150       *                              the associated attribute syntax.
151       */
152      public ByteString normalizeValue(ByteString value)
153             throws DirectoryException
154      {
155        StringBuilder buffer = new StringBuilder();
156        toLowerCase(value.value(), buffer, true);
157    
158        int bufferLength = buffer.length();
159        if (bufferLength == 0)
160        {
161          if (value.value().length > 0)
162          {
163            // This should only happen if the value is composed entirely of spaces.
164            // In that case, the normalized value is a single space.
165            return new ASN1OctetString(" ");
166          }
167          else
168          {
169            // The value is empty, so it is already normalized.
170            return new ASN1OctetString();
171          }
172        }
173    
174    
175        // Replace any consecutive spaces with a single space.
176        for (int pos = bufferLength-1; pos > 0; pos--)
177        {
178          if (buffer.charAt(pos) == ' ')
179          {
180            if (buffer.charAt(pos-1) == ' ')
181            {
182              buffer.delete(pos, pos+1);
183            }
184          }
185        }
186    
187        return new ASN1OctetString(buffer.toString());
188      }
189    
190    
191    
192      /**
193       * Indicates whether the two provided normalized values are equal to each
194       * other.
195       *
196       * @param  value1  The normalized form of the first value to compare.
197       * @param  value2  The normalized form of the second value to compare.
198       *
199       * @return  <CODE>true</CODE> if the provided values are equal, or
200       *          <CODE>false</CODE> if not.
201       */
202      public boolean areEqual(ByteString value1, ByteString value2)
203      {
204        // For this purpose, the first value will be considered the attribute value,
205        // and the second the assertion value.  See if the second value is contained
206        // in the first.  If not, then it isn't a match.
207        String valueStr1 = value1.stringValue();
208        String valueStr2 = value2.stringValue();
209        int pos = valueStr1.indexOf(valueStr2);
210        if (pos < 0)
211        {
212          return false;
213        }
214    
215    
216        if (pos > 0)
217        {
218          char c = valueStr1.charAt(pos-1);
219          switch (c)
220          {
221            case ' ':
222            case '.':
223            case ',':
224            case '/':
225            case '$':
226            case '+':
227            case '-':
228            case '_':
229            case '#':
230            case '=':
231              // These are all acceptable.
232              break;
233    
234            default:
235              // Anything else is not.
236              return false;
237          }
238        }
239    
240    
241        if (valueStr1.length() > (pos + valueStr2.length()))
242        {
243          char c = valueStr1.charAt(pos + valueStr2.length());
244          switch (c)
245          {
246            case ' ':
247            case '.':
248            case ',':
249            case '/':
250            case '$':
251            case '+':
252            case '-':
253            case '_':
254            case '#':
255            case '=':
256              // These are all acceptable.
257              break;
258    
259            default:
260              // Anything else is not.
261              return false;
262          }
263        }
264    
265    
266        // If we've gotten here, then we can assume it is a match.
267        return true;
268      }
269    
270    
271    
272      /**
273       * Generates a hash code for the provided attribute value.  This version of
274       * the method will simply create a hash code from the normalized form of the
275       * attribute value.  For matching rules explicitly designed to work in cases
276       * where byte-for-byte comparisons of normalized values is not sufficient for
277       * determining equality (e.g., if the associated attribute syntax is based on
278       * hashed or encrypted values), then this method must be overridden to provide
279       * an appropriate implementation for that case.
280       *
281       * @param  attributeValue  The attribute value for which to generate the hash
282       *                         code.
283       *
284       * @return  The hash code generated for the provided attribute value.*/
285      public int generateHashCode(AttributeValue attributeValue)
286      {
287        // In this case, we'll always return the same value because the matching
288        // isn't based on the entire value.
289        return 1;
290      }
291    }
292