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    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.Arrays;
033    
034    import org.opends.server.admin.std.server.EqualityMatchingRuleCfg;
035    import org.opends.server.api.EqualityMatchingRule;
036    import org.opends.server.config.ConfigException;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.types.ByteString;
040    import org.opends.server.types.DirectoryException;
041    import org.opends.server.types.InitializationException;
042    import org.opends.server.types.ResultCode;
043    
044    import static org.opends.messages.SchemaMessages.*;
045    import static org.opends.server.schema.SchemaConstants.*;
046    import org.opends.server.loggers.ErrorLogger;
047    
048    
049    /**
050     * This class implements the caseExactIA5Match matching rule defined in RFC
051     * 2252.
052     */
053    public class CaseExactIA5EqualityMatchingRule
054           extends EqualityMatchingRule
055    {
056      /**
057       * Creates a new instance of this caseExactMatch matching rule.
058       */
059      public CaseExactIA5EqualityMatchingRule()
060      {
061        super();
062      }
063    
064    
065    
066      /**
067       * {@inheritDoc}
068       */
069      public void initializeMatchingRule(EqualityMatchingRuleCfg configuration)
070             throws ConfigException, InitializationException
071      {
072        // No initialization is required.
073      }
074    
075    
076    
077      /**
078       * Retrieves the common name for this matching rule.
079       *
080       * @return  The common name for this matching rule, or <CODE>null</CODE> if
081       * it does not have a name.
082       */
083      public String getName()
084      {
085        return EMR_CASE_EXACT_IA5_NAME;
086      }
087    
088    
089    
090      /**
091       * Retrieves the OID for this matching rule.
092       *
093       * @return  The OID for this matching rule.
094       */
095      public String getOID()
096      {
097        return EMR_CASE_EXACT_IA5_OID;
098      }
099    
100    
101    
102      /**
103       * Retrieves the description for this matching rule.
104       *
105       * @return  The description for this matching rule, or <CODE>null</CODE> if
106       *          there is none.
107       */
108      public String getDescription()
109      {
110        // There is no standard description for this matching rule.
111        return null;
112      }
113    
114    
115    
116      /**
117       * Retrieves the OID of the syntax with which this matching rule is
118       * associated.
119       *
120       * @return  The OID of the syntax with which this matching rule is associated.
121       */
122      public String getSyntaxOID()
123      {
124        return SYNTAX_IA5_STRING_OID;
125      }
126    
127    
128    
129      /**
130       * Retrieves the normalized form of the provided value, which is best suited
131       * for efficiently performing matching operations on that value.
132       *
133       * @param  value  The value to be normalized.
134       *
135       * @return  The normalized version of the provided value.
136       *
137       * @throws  DirectoryException  If the provided value is invalid according to
138       *                              the associated attribute syntax.
139       */
140      public ByteString normalizeValue(ByteString value)
141             throws DirectoryException
142      {
143        StringBuilder buffer = new StringBuilder();
144        buffer.append(value.stringValue().trim());
145    
146        int bufferLength = buffer.length();
147        if (bufferLength == 0)
148        {
149          if (value.value().length > 0)
150          {
151            // This should only happen if the value is composed entirely of spaces.
152            // In that case, the normalized value is a single space.
153            return new ASN1OctetString(" ");
154          }
155          else
156          {
157            // The value is empty, so it is already normalized.
158            return new ASN1OctetString();
159          }
160        }
161    
162    
163        // Replace any consecutive spaces with a single space, and watch out for
164        // non-ASCII characters.
165        boolean logged = false;
166        for (int pos = bufferLength-1; pos > 0; pos--)
167        {
168          char c = buffer.charAt(pos);
169          if (c == ' ')
170          {
171            if (buffer.charAt(pos-1) == ' ')
172            {
173              buffer.delete(pos, pos+1);
174            }
175          }
176          else if ((c & 0x7F) != c)
177          {
178            // This is not a valid character for an IA5 string.  If strict syntax
179            // enforcement is enabled, then we'll throw an exception.  Otherwise,
180            // we'll get rid of the character.
181    
182            Message message = WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(
183                    value.stringValue(), String.valueOf(c));
184    
185            switch (DirectoryServer.getSyntaxEnforcementPolicy())
186            {
187              case REJECT:
188                throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
189                                             message);
190              case WARN:
191                if (! logged)
192                {
193                  ErrorLogger.logError(message);
194                  logged = true;
195                }
196    
197                buffer.delete(pos, pos+1);
198                break;
199    
200              default:
201                buffer.delete(pos, pos+1);
202                break;
203            }
204          }
205        }
206    
207        return new ASN1OctetString(buffer.toString());
208      }
209    
210    
211    
212      /**
213       * Indicates whether the two provided normalized values are equal to each
214       * other.
215       *
216       * @param  value1  The normalized form of the first value to compare.
217       * @param  value2  The normalized form of the second value to compare.
218       *
219       * @return  <CODE>true</CODE> if the provided values are equal, or
220       *          <CODE>false</CODE> if not.
221       */
222      public boolean areEqual(ByteString value1, ByteString value2)
223      {
224        // Since the values are already normalized, we just need to compare the
225        // associated byte arrays.
226        return Arrays.equals(value1.value(), value2.value());
227      }
228    }
229