001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.api.ldap.model.schema.syntaxCheckers;
021
022
023import java.util.HashSet;
024import java.util.Set;
025
026import org.apache.directory.api.i18n.I18n;
027import org.apache.directory.api.ldap.model.constants.SchemaConstants;
028import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
029import org.apache.directory.api.util.Strings;
030
031
032/**
033 * A SyntaxChecker which verifies that a value is a country according to RFC 4517.
034 * 
035 * From RFC 4517 :
036 * 
037 * <pre>
038 * A value of the Country String syntax is one of the two-character
039 * codes from ISO 3166 [ISO3166] for representing a country.
040 * </pre>
041 *
042 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
043 */
044@SuppressWarnings("serial")
045public final class CountrySyntaxChecker extends SyntaxChecker
046{
047    /** The ISO 3166 list of countries, as of 2006 */
048    private static final String[] COUNTRY_ISO_3166 =
049        {
050            "AD",
051            "AE",
052            "AF",
053            "AG",
054            "AI",
055            "AL",
056            "AM",
057            "AN",
058            "AO",
059            "AQ",
060            "AR",
061            "AS",
062            "AT",
063            "AU",
064            "AW",
065            "AX",
066            "AZ",
067            "BA",
068            "BB",
069            "BD",
070            "BE",
071            "BF",
072            "BG",
073            "BH",
074            "BI",
075            "BJ",
076            "BM",
077            "BN",
078            "BO",
079            "BR",
080            "BS",
081            "BT",
082            "BV",
083            "BW",
084            "BY",
085            "BZ",
086            "CA",
087            "CC",
088            "CD",
089            "CF",
090            "CG",
091            "CH",
092            "CI",
093            "CK",
094            "CL",
095            "CM",
096            "CN",
097            "CO",
098            "CR",
099            "CU",
100            "CV",
101            "CX",
102            "CY",
103            "CZ",
104            "DE",
105            "DJ",
106            "DK",
107            "DM",
108            "DO",
109            "DZ",
110            "EC",
111            "EE",
112            "EG",
113            "EH",
114            "ER",
115            "ES",
116            "ET",
117            "FI",
118            "FJ",
119            "FK",
120            "FM",
121            "FO",
122            "FR",
123            "GA",
124            "GB",
125            "GD",
126            "GE",
127            "GG",
128            "GF",
129            "GH",
130            "GI",
131            "GL",
132            "GM",
133            "GN",
134            "GP",
135            "GQ",
136            "GR",
137            "GS",
138            "GT",
139            "GU",
140            "GW",
141            "GY",
142            "HK",
143            "HM",
144            "HN",
145            "HR",
146            "HT",
147            "HU",
148            "ID",
149            "IE",
150            "IL",
151            "IM",
152            "IN",
153            "IO",
154            "IQ",
155            "IR",
156            "IS",
157            "IT",
158            "JE",
159            "JM",
160            "JO",
161            "JP",
162            "KE",
163            "KG",
164            "KH",
165            "KI",
166            "KM",
167            "KN",
168            "KP",
169            "KR",
170            "KW",
171            "KY",
172            "KZ",
173            "LA",
174            "LB",
175            "LC",
176            "LI",
177            "LK",
178            "LR",
179            "LS",
180            "LT",
181            "LU",
182            "LV",
183            "LY",
184            "MA",
185            "MC",
186            "MD",
187            "ME",
188            "MG",
189            "MH",
190            "MK",
191            "ML",
192            "MM",
193            "MN",
194            "MO",
195            "MP",
196            "MQ",
197            "MR",
198            "MS",
199            "MT",
200            "MU",
201            "MV",
202            "MW",
203            "MX",
204            "MY",
205            "MZ",
206            "NA",
207            "NC",
208            "NE",
209            "NF",
210            "NG",
211            "NI",
212            "NL",
213            "NO",
214            "NP",
215            "NR",
216            "NU",
217            "NZ",
218            "OM",
219            "PA",
220            "PE",
221            "PF",
222            "PG",
223            "PH",
224            "PK",
225            "PL",
226            "PM",
227            "PN",
228            "PR",
229            "PS",
230            "PT",
231            "PW",
232            "PY",
233            "QA",
234            "RE",
235            "RO",
236            "RS",
237            "RU",
238            "RW",
239            "SA",
240            "SB",
241            "SC",
242            "SD",
243            "SE",
244            "SG",
245            "SH",
246            "SI",
247            "SJ",
248            "SK",
249            "SL",
250            "SM",
251            "SN",
252            "SO",
253            "SR",
254            "ST",
255            "SV",
256            "SY",
257            "SZ",
258            "TC",
259            "TD",
260            "TF",
261            "TG",
262            "TH",
263            "TJ",
264            "TK",
265            "TL",
266            "TM",
267            "TN",
268            "TO",
269            "TR",
270            "TT",
271            "TV",
272            "TW",
273            "TZ",
274            "UA",
275            "UG",
276            "UM",
277            "US",
278            "UY",
279            "UZ",
280            "VA",
281            "VC",
282            "VE",
283            "VG",
284            "VI",
285            "VN",
286            "VU",
287            "WF",
288            "WS",
289            "YE",
290            "YT",
291            "ZA",
292            "ZM",
293            "ZW"
294    };
295
296    /** The Set which contains the countries */
297    private static final Set<String> COUNTRIES = new HashSet<>();
298
299    /** Initialization of the country set */
300    static
301    {
302        for ( String country : COUNTRY_ISO_3166 )
303        {
304            COUNTRIES.add( country );
305        }
306    }
307    
308    /**
309     * A static instance of CountrySyntaxChecker
310     */
311    public static final CountrySyntaxChecker INSTANCE = new CountrySyntaxChecker( SchemaConstants.COUNTRY_STRING_SYNTAX );
312
313    /**
314     * A static Builder for this class
315     */
316    public static final class Builder extends SCBuilder<CountrySyntaxChecker>
317    {
318        /**
319         * The Builder constructor
320         */
321        private Builder()
322        {
323            super( SchemaConstants.COUNTRY_STRING_SYNTAX );
324        }
325        
326        
327        /**
328         * Create a new instance of CountrySyntaxChecker
329         * @return A new instance of CountrySyntaxChecker
330         */
331        @Override
332        public CountrySyntaxChecker build()
333        {
334            return new CountrySyntaxChecker( oid );
335        }
336    }
337
338
339    /**
340     * Creates a new instance of CountrySyntaxChecker.
341     *
342     * @param oid The OID to use for this SyntaxChecker
343     */
344    private CountrySyntaxChecker( String oid )
345    {
346        super( oid );
347    }
348
349    
350    /**
351     * @return An instance of the Builder for this class
352     */
353    public static Builder builder()
354    {
355        return new Builder();
356    }
357
358
359    /**
360     * {@inheritDoc}
361     */
362    @Override
363    public boolean isValidSyntax( Object value )
364    {
365        String strValue;
366
367        if ( value == null )
368        {
369            if ( LOG.isDebugEnabled() )
370            {
371                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) );
372            }
373            
374            return false;
375        }
376
377        if ( value instanceof String )
378        {
379            strValue = ( String ) value;
380        }
381        else if ( value instanceof byte[] )
382        {
383            strValue = Strings.utf8ToString( ( byte[] ) value );
384        }
385        else
386        {
387            strValue = value.toString();
388        }
389
390        if ( strValue.length() == 0 )
391        {
392            if ( LOG.isDebugEnabled() )
393            {
394                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
395            }
396            
397            return false;
398        }
399
400        boolean result = COUNTRIES.contains( Strings.toUpperCaseAscii( strValue ) );
401
402        if ( LOG.isDebugEnabled() )
403        {
404            if ( result )
405            {
406                LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
407            }
408            else
409            {
410                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
411            }
412        }
413
414        return result;
415    }
416}