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 java.util.HashSet;
032    
033    import org.opends.server.admin.std.server.AttributeSyntaxCfg;
034    import org.opends.server.api.ApproximateMatchingRule;
035    import org.opends.server.api.AttributeSyntax;
036    import org.opends.server.api.EqualityMatchingRule;
037    import org.opends.server.api.OrderingMatchingRule;
038    import org.opends.server.api.SubstringMatchingRule;
039    import org.opends.server.config.ConfigException;
040    import org.opends.server.core.DirectoryServer;
041    import org.opends.server.types.ByteString;
042    
043    
044    
045    import static org.opends.server.loggers.ErrorLogger.*;
046    import static org.opends.messages.SchemaMessages.*;
047    import org.opends.messages.MessageBuilder;
048    import static org.opends.server.schema.SchemaConstants.*;
049    
050    
051    
052    /**
053     * This class implements the teletex terminal identifier attribute syntax, which
054     * contains a printable string (the terminal identifier) followed by zero or
055     * more parameters, which start with a dollar sign and are followed by a
056     * parameter name, a colon, and a value.  The parameter value should consist of
057     * any string of bytes (the dollar sign and backslash must be escaped with a
058     * preceding backslash), and the parameter name must be one of the following
059     * strings:
060     * <UL>
061     *   <LI>graphic</LI>
062     *   <LI>control</LI>
063     *   <LI>misc</LI>
064     *   <LI>page</LI>
065     *   <LI>private</LI>
066     * </UL>
067     */
068    public class TeletexTerminalIdentifierSyntax
069           extends AttributeSyntax<AttributeSyntaxCfg>
070    {
071      /**
072       * The set of allowed fax parameter values, formatted entirely in lowercase
073       * characters.
074       */
075      public static final HashSet<String> ALLOWED_TTX_PARAMETERS =
076           new HashSet<String>(5);
077    
078      static
079      {
080        ALLOWED_TTX_PARAMETERS.add("graphic");
081        ALLOWED_TTX_PARAMETERS.add("control");
082        ALLOWED_TTX_PARAMETERS.add("misc");
083        ALLOWED_TTX_PARAMETERS.add("page");
084        ALLOWED_TTX_PARAMETERS.add("private");
085      }
086    
087    
088    
089      // The default equality matching rule for this syntax.
090      private EqualityMatchingRule defaultEqualityMatchingRule;
091    
092      // The default ordering matching rule for this syntax.
093      private OrderingMatchingRule defaultOrderingMatchingRule;
094    
095      // The default substring matching rule for this syntax.
096      private SubstringMatchingRule defaultSubstringMatchingRule;
097    
098    
099    
100      /**
101       * Creates a new instance of this syntax.  Note that the only thing that
102       * should be done here is to invoke the default constructor for the
103       * superclass.  All initialization should be performed in the
104       * <CODE>initializeSyntax</CODE> method.
105       */
106      public TeletexTerminalIdentifierSyntax()
107      {
108        super();
109      }
110    
111    
112    
113      /**
114       * {@inheritDoc}
115       */
116      public void initializeSyntax(AttributeSyntaxCfg configuration)
117             throws ConfigException
118      {
119        defaultEqualityMatchingRule =
120             DirectoryServer.getEqualityMatchingRule(EMR_CASE_IGNORE_OID);
121        if (defaultEqualityMatchingRule == null)
122        {
123          logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
124              EMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
125        }
126    
127        defaultOrderingMatchingRule =
128             DirectoryServer.getOrderingMatchingRule(OMR_CASE_IGNORE_OID);
129        if (defaultOrderingMatchingRule == null)
130        {
131          logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
132              OMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
133        }
134    
135        defaultSubstringMatchingRule =
136             DirectoryServer.getSubstringMatchingRule(SMR_CASE_IGNORE_OID);
137        if (defaultSubstringMatchingRule == null)
138        {
139          logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
140              SMR_CASE_IGNORE_OID, SYNTAX_TELETEX_TERM_ID_NAME));
141        }
142      }
143    
144    
145    
146      /**
147       * Retrieves the common name for this attribute syntax.
148       *
149       * @return  The common name for this attribute syntax.
150       */
151      public String getSyntaxName()
152      {
153        return SYNTAX_TELETEX_TERM_ID_NAME;
154      }
155    
156    
157    
158      /**
159       * Retrieves the OID for this attribute syntax.
160       *
161       * @return  The OID for this attribute syntax.
162       */
163      public String getOID()
164      {
165        return SYNTAX_TELETEX_TERM_ID_OID;
166      }
167    
168    
169    
170      /**
171       * Retrieves a description for this attribute syntax.
172       *
173       * @return  A description for this attribute syntax.
174       */
175      public String getDescription()
176      {
177        return SYNTAX_TELETEX_TERM_ID_DESCRIPTION;
178      }
179    
180    
181    
182      /**
183       * Retrieves the default equality matching rule that will be used for
184       * attributes with this syntax.
185       *
186       * @return  The default equality matching rule that will be used for
187       *          attributes with this syntax, or <CODE>null</CODE> if equality
188       *          matches will not be allowed for this type by default.
189       */
190      public EqualityMatchingRule getEqualityMatchingRule()
191      {
192        return defaultEqualityMatchingRule;
193      }
194    
195    
196    
197      /**
198       * Retrieves the default ordering matching rule that will be used for
199       * attributes with this syntax.
200       *
201       * @return  The default ordering matching rule that will be used for
202       *          attributes with this syntax, or <CODE>null</CODE> if ordering
203       *          matches will not be allowed for this type by default.
204       */
205      public OrderingMatchingRule getOrderingMatchingRule()
206      {
207        return defaultOrderingMatchingRule;
208      }
209    
210    
211    
212      /**
213       * Retrieves the default substring matching rule that will be used for
214       * attributes with this syntax.
215       *
216       * @return  The default substring matching rule that will be used for
217       *          attributes with this syntax, or <CODE>null</CODE> if substring
218       *          matches will not be allowed for this type by default.
219       */
220      public SubstringMatchingRule getSubstringMatchingRule()
221      {
222        return defaultSubstringMatchingRule;
223      }
224    
225    
226    
227      /**
228       * Retrieves the default approximate matching rule that will be used for
229       * attributes with this syntax.
230       *
231       * @return  The default approximate matching rule that will be used for
232       *          attributes with this syntax, or <CODE>null</CODE> if approximate
233       *          matches will not be allowed for this type by default.
234       */
235      public ApproximateMatchingRule getApproximateMatchingRule()
236      {
237        // There is no approximate matching rule by default.
238        return null;
239      }
240    
241    
242    
243      /**
244       * Indicates whether the provided value is acceptable for use in an attribute
245       * with this syntax.  If it is not, then the reason may be appended to the
246       * provided buffer.
247       *
248       * @param  value          The value for which to make the determination.
249       * @param  invalidReason  The buffer to which the invalid reason should be
250       *                        appended.
251       *
252       * @return  <CODE>true</CODE> if the provided value is acceptable for use with
253       *          this syntax, or <CODE>false</CODE> if not.
254       */
255      public boolean valueIsAcceptable(ByteString value,
256                                       MessageBuilder invalidReason)
257      {
258        // Get a lowercase string representation of the value and find its length.
259        String valueString = value.stringValue();
260        int    valueLength = valueString.length();
261    
262    
263        // The value must contain at least one character.
264        if (valueLength == 0)
265        {
266    
267          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_EMPTY.get());
268          return false;
269        }
270    
271    
272        // The first character must be a printable string character.
273        char c = valueString.charAt(0);
274        if (! PrintableString.isPrintableCharacter(c))
275        {
276    
277          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
278                  valueString, String.valueOf(c), 0));
279          return false;
280        }
281    
282    
283        // Continue reading until we find a dollar sign or the end of the string.
284        // Every intermediate character must be a printable string character.
285        int pos = 1;
286        for ( ; pos < valueLength; pos++)
287        {
288          c = valueString.charAt(pos);
289          if (c == '$')
290          {
291            pos++;
292            break;
293          }
294          else
295          {
296            if (! PrintableString.isPrintableCharacter(c))
297            {
298    
299              invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_NOT_PRINTABLE.get(
300                      valueString, String.valueOf(c), pos));
301            }
302          }
303        }
304    
305        if (pos >= valueLength)
306        {
307          // We're at the end of the value, so it must be valid unless the last
308          // character was a dollar sign.
309          if (c == '$')
310          {
311    
312            invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_END_WITH_DOLLAR.get(
313                    valueString));
314            return false;
315          }
316          else
317          {
318            return true;
319          }
320        }
321    
322    
323        // Continue reading until we find the end of the string.  Each substring
324        // must be a valid teletex terminal identifier parameter followed by a colon
325        // and the value.  Dollar signs must be escaped
326        int paramStartPos = pos;
327        boolean escaped = false;
328        while (pos < valueLength)
329        {
330          if (escaped)
331          {
332            pos++;
333            continue;
334          }
335    
336          c = valueString.charAt(pos++);
337          if (c == '\\')
338          {
339            escaped = true;
340            continue;
341          }
342          else if (c == '$')
343          {
344            String paramStr = valueString.substring(paramStartPos, pos);
345    
346            int colonPos = paramStr.indexOf(':');
347            if (colonPos < 0)
348            {
349    
350              invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON.get(
351                      valueString));
352              return false;
353            }
354    
355            String paramName = paramStr.substring(0, colonPos);
356            if (! ALLOWED_TTX_PARAMETERS.contains(paramName))
357            {
358    
359              invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
360                      valueString, paramName));
361              return false;
362            }
363    
364            paramStartPos = pos;
365          }
366        }
367    
368    
369        // We must be at the end of the value.  Read the last parameter and make
370        // sure it is valid.
371        String paramStr = valueString.substring(paramStartPos);
372        int colonPos = paramStr.indexOf(':');
373        if (colonPos < 0)
374        {
375    
376          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_PARAM_NO_COLON.get(
377                  valueString));
378          return false;
379        }
380    
381        String paramName = paramStr.substring(0, colonPos);
382        if (! ALLOWED_TTX_PARAMETERS.contains(paramName))
383        {
384    
385          invalidReason.append(ERR_ATTR_SYNTAX_TELETEXID_ILLEGAL_PARAMETER.get(
386                  valueString, paramName));
387          return false;
388        }
389    
390    
391        // If we've gotten here, then the value must be valid.
392        return true;
393      }
394    }
395