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.ldap.model.constants.SchemaConstants;
027import org.apache.directory.api.util.Strings;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031
032/**
033 * A SyntaxChecker which verifies that a value is a facsimile TelephoneNumber according 
034 * to ITU recommendation E.123 for the Telephone number part, and from RFC 4517, par. 
035 * 3.3.11 :
036 * 
037 * fax-number       = telephone-number *( DOLLAR fax-parameter )
038 * telephone-number = PrintableString
039 * fax-parameter    = "twoDimensional" |
040 *                    "fineResolution" |
041 *                    "unlimitedLength" |
042 *                    "b4Length" |
043 *                    "a3Width" |
044 *                    "b4Width" |
045 *                    "uncompressed"
046 *
047 * 
048 * If needed, and to allow more syntaxes, a list of regexps has been added
049 * which can be initialized to other values
050 * 
051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052 */
053@SuppressWarnings("serial")
054public class FacsimileTelephoneNumberSyntaxChecker extends TelephoneNumberSyntaxChecker
055{
056    /** A logger for this class */
057    private static final Logger LOG = LoggerFactory.getLogger( FacsimileTelephoneNumberSyntaxChecker.class );
058
059    /** Fax parameters possible values */
060    private static final String TWO_DIMENSIONAL = "twoDimensional";
061    private static final String FINE_RESOLUTION = "fineResolution";
062    private static final String UNLIMITED_LENGTH = "unlimitedLength";
063    private static final String B4_LENGTH = "b4Length";
064    private static final String A3_LENGTH = "a3Width";
065    private static final String B4_WIDTH = "b4Width";
066    private static final String UNCOMPRESSED = "uncompressed";
067
068    /** A set which contaons all the possible fax parameters values */
069    private static Set<String> faxParameters = new HashSet<String>();
070
071    /** Initialization of the fax parameters set of values */
072    static
073    {
074        faxParameters.add( Strings.toLowerCase( TWO_DIMENSIONAL ) );
075        faxParameters.add( Strings.toLowerCase( FINE_RESOLUTION ) );
076        faxParameters.add( Strings.toLowerCase( UNLIMITED_LENGTH ) );
077        faxParameters.add( Strings.toLowerCase( B4_LENGTH ) );
078        faxParameters.add( Strings.toLowerCase( A3_LENGTH ) );
079        faxParameters.add( Strings.toLowerCase( B4_WIDTH ) );
080        faxParameters.add( Strings.toLowerCase( UNCOMPRESSED ) );
081    }
082
083
084    /**
085     * Creates a new instance of TelephoneNumberSyntaxChecker.
086     */
087    public FacsimileTelephoneNumberSyntaxChecker()
088    {
089        super();
090        setOid( SchemaConstants.FACSIMILE_TELEPHONE_NUMBER_SYNTAX );
091    }
092
093
094    /**
095     * {@inheritDoc}
096     */
097    public boolean isValidSyntax( Object value )
098    {
099        String strValue = null;
100
101        if ( value == null )
102        {
103            LOG.debug( "Syntax invalid for 'null'" );
104            return false;
105        }
106
107        if ( value instanceof String )
108        {
109            strValue = ( String ) value;
110        }
111        else if ( value instanceof byte[] )
112        {
113            strValue = Strings.utf8ToString( ( byte[] ) value );
114        }
115        else
116        {
117            strValue = value.toString();
118        }
119
120        if ( strValue.length() == 0 )
121        {
122            LOG.debug( "Syntax invalid for '{}'", value );
123            return false;
124        }
125
126        // The facsimile telephone number might be composed
127        // of two parts separated by a '$'.
128        int dollarPos = strValue.indexOf( '$' );
129
130        if ( dollarPos == -1 )
131        {
132            // We have no fax-parameter : check the Telephone number
133            boolean result = super.isValidSyntax( strValue );
134
135            if ( result )
136            {
137                LOG.debug( "Syntax valid for '{}'", value );
138            }
139            else
140            {
141                LOG.debug( "Syntax invalid for '{}'", value );
142            }
143
144            return result;
145        }
146
147        // First check the telephone number if the '$' is not at the first position
148        if ( dollarPos > 0 )
149        {
150            if ( !super.isValidSyntax( strValue.substring( 0, dollarPos - 1 ) ) )
151            {
152                LOG.debug( "Syntax invalid for '{}'", value );
153                return false;
154            }
155
156            // Now, try to validate the fax-parameters : we may
157            // have more than one, so we will store the seen params
158            // in a set to check that we don't have the same param twice
159            Set<String> paramsSeen = new HashSet<String>();
160
161            while ( dollarPos > 0 )
162            {
163                String faxParam = null;
164                int newDollar = strValue.indexOf( '$', dollarPos + 1 );
165
166                if ( newDollar == -1 )
167                {
168                    faxParam = strValue.substring( dollarPos + 1 );
169                }
170                else
171                {
172                    faxParam = strValue.substring( dollarPos + 1, newDollar );
173                }
174
175                if ( faxParam.length() == 0 )
176                {
177                    // Not allowed
178                    LOG.debug( "Syntax invalid for '{}'", value );
179                    return false;
180                }
181
182                // Relax a little bit the syntax by lowercasing the param
183                faxParam = Strings.toLowerCase( faxParam );
184
185                if ( !faxParameters.contains( faxParam ) )
186                {
187                    // This parameter is not in the possible set
188                    LOG.debug( "Syntax invalid for '{}'", value );
189                    return false;
190                }
191                else if ( paramsSeen.contains( faxParam ) )
192                {
193                    // We have the same parameters twice...
194                    LOG.debug( "Syntax invalid for '{}'", value );
195                    return false;
196                }
197                else
198                {
199                    // It's a correct param, let's add it to the seen 
200                    // params.
201                    paramsSeen.add( faxParam );
202                }
203
204                dollarPos = newDollar;
205            }
206
207            LOG.debug( "Syntax valid for '{}'", value );
208            return true;
209        }
210
211        // We must have a valid telephone number !
212        LOG.debug( "Syntax invalid for '{}'", value );
213        return false;
214    }
215}