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.shared.ldap.model.schema.syntaxCheckers;
021
022
023import java.util.HashSet;
024import java.util.Set;
025
026import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
027import org.apache.directory.shared.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( TWO_DIMENSIONAL.toLowerCase() );
075        faxParameters.add( FINE_RESOLUTION.toLowerCase() );
076        faxParameters.add( UNLIMITED_LENGTH.toLowerCase() );
077        faxParameters.add( B4_LENGTH.toLowerCase() );
078        faxParameters.add( A3_LENGTH.toLowerCase() );
079        faxParameters.add( B4_WIDTH.toLowerCase() );
080        faxParameters.add( UNCOMPRESSED.toLowerCase() );
081    }
082    
083    /**
084     * Creates a new instance of TelephoneNumberSyntaxChecker.
085     */
086    public FacsimileTelephoneNumberSyntaxChecker()
087    {
088        super();
089        setOid( SchemaConstants.FACSIMILE_TELEPHONE_NUMBER_SYNTAX );
090    }
091
092
093    /**
094     * {@inheritDoc}
095     */
096    public boolean isValidSyntax( Object value )
097    {
098        String strValue = null;
099
100        if ( value == null )
101        {
102            LOG.debug( "Syntax invalid for 'null'" );
103            return false;
104        }
105        
106        if ( value instanceof String )
107        {
108            strValue = ( String ) value;
109        }
110        else if ( value instanceof byte[] )
111        {
112            strValue = Strings.utf8ToString((byte[]) value);
113        }
114        else
115        {
116            strValue = value.toString();
117        }
118
119        if ( strValue.length() == 0 )
120        {
121            LOG.debug( "Syntax invalid for '{}'", value );
122            return false;
123        }
124        
125        // The facsimile telephone number might be composed
126        // of two parts separated by a '$'.
127        int dollarPos = strValue.indexOf( '$' );
128        
129        if ( dollarPos == -1 )
130        {
131            // We have no fax-parameter : check the Telephone number
132            boolean result = super.isValidSyntax( strValue );
133            
134            if ( result )
135            {
136                LOG.debug( "Syntax valid for '{}'", value );
137            }
138            else
139            {
140                LOG.debug( "Syntax invalid for '{}'", value );
141            }
142            
143            return result;
144        }
145        
146        // First check the telephone number if the '$' is not at the first position
147        if ( dollarPos > 0 )
148        {
149            if ( !super.isValidSyntax( strValue.substring( 0, dollarPos -1 ) ) )
150            {
151                LOG.debug( "Syntax invalid for '{}'", value );
152                return false;
153            }
154            
155            // Now, try to validate the fax-parameters : we may
156            // have more than one, so we will store the seen params
157            // in a set to check that we don't have the same param twice
158            Set<String> paramsSeen = new HashSet<String>(); 
159           
160            while ( dollarPos > 0 )
161            {
162                String faxParam = null;
163                int newDollar = strValue.indexOf( '$', dollarPos + 1 );
164
165                if ( newDollar == -1 )
166                {
167                    faxParam = strValue.substring(  dollarPos+1 );
168                }
169                else
170                {
171                    faxParam = strValue.substring(  dollarPos+1, newDollar );
172                }
173                
174                if ( faxParam == null )
175                {
176                    // Not allowed
177                    LOG.debug( "Syntax invalid for '{}'", value );
178                    return false;
179                }
180                
181                // Relax a little bit the syntax by lowercasing the param
182                faxParam = faxParam.toLowerCase();
183                
184                if ( !faxParameters.contains( faxParam ) )
185                {
186                    // This parameter is not in the possible set
187                    LOG.debug( "Syntax invalid for '{}'", value );
188                    return false;
189                }
190                else if ( paramsSeen.contains( faxParam ) )
191                {
192                    // We have the same parameters twice...
193                    LOG.debug( "Syntax invalid for '{}'", value );
194                    return false;
195                } 
196                else
197                {
198                    // It's a correct param, let's add it to the seen 
199                    // params.
200                    paramsSeen.add( faxParam );
201                }
202                
203                dollarPos = newDollar;
204            }
205            
206            LOG.debug( "Syntax valid for '{}'", value );
207            return true;
208        }
209        
210        // We must have a valid telephone number !
211        LOG.debug( "Syntax invalid for '{}'", value );
212        return false;
213    }
214}