View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
21  
22  
23  import java.util.HashSet;
24  import java.util.Set;
25  
26  import org.apache.directory.api.i18n.I18n;
27  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
28  import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
29  import org.apache.directory.api.util.Chars;
30  import org.apache.directory.api.util.Strings;
31  
32  
33  /**
34   * A SyntaxChecker which verifies that a value is a delivery method 
35   * according to RFC 4517.
36   * 
37   * From RFC 4517 & RFC 4512:
38   * <pre>
39   * DeliveryMethod = pdm *( WSP DOLLAR WSP pdm )
40   *
41   * pdm = "any" | "mhs" | "physical" | "telex" | "teletex" |
42   *       "g3fax" | "g4fax" | "ia5" | "videotex" | "telephone"
43   *           
44   * WSP     = 0*SPACE  ; zero or more " "
45   * DOLLAR  = %x24 ; dollar sign ("$")
46   * SPACE   = %x20 ; space (" ")
47   * </pre>
48   *
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  @SuppressWarnings("serial")
52  public final class DeliveryMethodSyntaxChecker extends SyntaxChecker
53  {
54      private static final String[] PDMS =
55          {
56              "any", "mhs", "physical", "telex", "teletex",
57              "g3fax", "g4fax", "ia5", "videotex", "telephone"
58          };
59  
60      /** The Set which contains the delivery methods */
61      private static final Set<String> DELIVERY_METHODS = new HashSet<>();
62  
63      /** Initialization of the delivery methods set */
64      static
65      {
66          for ( String country : PDMS )
67          {
68              DELIVERY_METHODS.add( country );
69          }
70      }
71      
72      /**
73       * A static instance of DeliveryMethodSyntaxChecker
74       */
75      public static final DeliveryMethodSyntaxChecker INSTANCE = 
76          new DeliveryMethodSyntaxChecker( SchemaConstants.DELIVERY_METHOD_SYNTAX );
77      
78      /**
79       * A static Builder for this class
80       */
81      public static final class Builder extends SCBuilder<DeliveryMethodSyntaxChecker>
82      {
83          /**
84           * The Builder constructor
85           */
86          private Builder()
87          {
88              super( SchemaConstants.DELIVERY_METHOD_SYNTAX );
89          }
90          
91          
92          /**
93           * Create a new instance of DeliveryMethodSyntaxChecker
94           * @return A new instance of DeliveryMethodSyntaxChecker
95           */
96          @Override
97          public DeliveryMethodSyntaxChecker build()
98          {
99              return new DeliveryMethodSyntaxChecker( oid );
100         }
101     }
102 
103 
104     /**
105      * Creates a new instance of DeliveryMethodSyntaxChecker.
106      *
107      * @param oid The OID to use for this SyntaxChecker
108      */
109     private DeliveryMethodSyntaxChecker( String oid )
110     {
111         super( oid );
112     }
113 
114     
115     /**
116      * @return An instance of the Builder for this class
117      */
118     public static Builder builder()
119     {
120         return new Builder();
121     }
122 
123 
124     /**
125      * 
126      * Check if the string contains a delivery method which has 
127      * not already been found.
128      * 
129      * @param strValue The string we want to look into for a PDM 
130      * @param pos The current position in the string
131      * @param pdms The set containing all the PDM
132      * @return if a Prefered Delivery Method is found in the given string, returns 
133      * its position, otherwise, returns -1
134      */
135     private int isPdm( String strValue, int start, Set<String> pdms )
136     {
137         int pos = start;
138 
139         while ( Chars.isAlphaDigit( strValue, pos ) )
140         {
141             pos++;
142         }
143 
144         // No ascii string, this is not a delivery method
145         if ( pos == start )
146         {
147             return -1;
148         }
149 
150         String pdm = strValue.substring( start, pos );
151 
152         if ( !DELIVERY_METHODS.contains( pdm ) )
153         {
154             // The delivery method is unknown
155             return -1;
156         }
157         else
158         {
159             if ( pdms.contains( pdm ) )
160             {
161                 // The delivery method has already been found
162                 return -1;
163             }
164             else
165             {
166                 pdms.add( pdm );
167                 return pos;
168             }
169         }
170     }
171 
172 
173     /**
174      * {@inheritDoc}
175      */
176     @Override
177     public boolean isValidSyntax( Object value )
178     {
179         String strValue;
180 
181         if ( value == null )
182         {
183             if ( LOG.isDebugEnabled() )
184             {
185                 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) );
186             }
187             
188             return false;
189         }
190 
191         if ( value instanceof String )
192         {
193             strValue = ( String ) value;
194         }
195         else if ( value instanceof byte[] )
196         {
197             strValue = Strings.utf8ToString( ( byte[] ) value );
198         }
199         else
200         {
201             strValue = value.toString();
202         }
203 
204         if ( strValue.length() == 0 )
205         {
206             if ( LOG.isDebugEnabled() )
207             {
208                 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
209             }
210             
211             return false;
212         }
213 
214         // We will get the first delivery method
215         int length = strValue.length();
216         int pos = 0;
217         Set<String> pmds = new HashSet<>();
218 
219         pos = isPdm( strValue, pos, pmds );
220         
221         if ( pos == -1 )
222         {
223             if ( LOG.isDebugEnabled() )
224             {
225                 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
226             }
227             
228             return false;
229         }
230 
231         // We have found at least the first pmd,
232         // now iterate through the other ones. We may have
233         // SP* '$' SP* before each pmd.
234         while ( pos < length )
235         {
236             // Skip spaces
237             while ( Strings.isCharASCII( strValue, pos, ' ' ) )
238             {
239                 pos++;
240             }
241 
242             if ( !Strings.isCharASCII( strValue, pos, '$' ) )
243             {
244                 // A '$' was expected
245                 if ( LOG.isDebugEnabled() )
246                 {
247                     LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
248                 }
249                 
250                 return false;
251             }
252             else
253             {
254                 pos++;
255             }
256 
257             // Skip spaces
258             while ( Strings.isCharASCII( strValue, pos, ' ' ) )
259             {
260                 pos++;
261             }
262 
263             pos = isPdm( strValue, pos, pmds );
264             
265             if ( pos == -1 )
266             {
267                 if ( LOG.isDebugEnabled() )
268                 {
269                     LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
270                 }
271                 
272                 return false;
273             }
274         }
275 
276         if ( LOG.isDebugEnabled() )
277         {
278             LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
279         }
280         
281         return true;
282     }
283 }