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.ArrayList;
024import java.util.List;
025import java.util.regex.Pattern;
026import java.util.regex.PatternSyntaxException;
027
028import org.apache.directory.api.ldap.model.constants.SchemaConstants;
029import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
030import org.apache.directory.api.util.Strings;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034
035/**
036 * A SyntaxChecker which verifies that a value is a TelephoneNumber according to ITU
037 * recommendation E.123 (which is quite vague ...).
038 * 
039 * A valid Telephone number respect more or less this syntax :
040 * 
041 * " *[+]? *((\([0-9- ]+\))|[0-9- ]+)+"
042 * 
043 * If needed, and to allow more syntaxes, a list of regexps has been added
044 * which can be initialized to other values
045 * 
046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047 */
048@SuppressWarnings("serial")
049public class TelephoneNumberSyntaxChecker extends SyntaxChecker
050{
051    /** A logger for this class */
052    private static final Logger LOG = LoggerFactory.getLogger( TelephoneNumberSyntaxChecker.class );
053
054    /** Other regexps to extend the initial one */
055    private List<String> regexps;
056
057    /** Other regexp to extend the initial one, compiled */
058    private List<Pattern> compiledREs;
059
060    /** The default pattern used to check a TelephoneNumber */
061    private static final String DEFAULT_REGEXP = "^ *[+]? *((\\([0-9- ,;#*]+\\))|[0-9- ,;#*]+)+$";
062
063    /** The compiled default pattern */
064    private Pattern defaultPattern = Pattern.compile( DEFAULT_REGEXP );
065
066    /** A flag set when only the default regexp should be tested */
067    protected boolean defaultMandatory = false;
068
069
070    /**
071     * Creates a new instance of TelephoneNumberSyntaxChecker.
072     */
073    public TelephoneNumberSyntaxChecker()
074    {
075        super( SchemaConstants.TELEPHONE_NUMBER_SYNTAX );
076    }
077
078
079    /**
080     * Add a new valid regexp for a Telephone number
081     * @param regexp The new regexp to check
082     */
083    public void addRegexp( String regexp )
084    {
085        if ( defaultMandatory )
086        {
087            return;
088        }
089
090        try
091        {
092            Pattern compiledRE = Pattern.compile( regexp );
093
094            if ( regexps == null )
095            {
096                regexps = new ArrayList<String>();
097                compiledREs = new ArrayList<Pattern>();
098            }
099
100            regexps.add( regexp );
101            compiledREs.add( compiledRE );
102        }
103        catch ( PatternSyntaxException pse )
104        {
105            return;
106        }
107    }
108
109
110    /**
111     * Set the defaut regular expression for the Telephone number
112     * 
113     * @param regexp the default regular expression.
114     */
115    public void setDefaultRegexp( String regexp )
116    {
117        try
118        {
119            defaultPattern = Pattern.compile( regexp );
120
121            defaultMandatory = true;
122            regexps = null;
123            compiledREs = null;
124        }
125        catch ( PatternSyntaxException pse )
126        {
127            return;
128        }
129    }
130
131
132    /**
133     * {@inheritDoc}
134     */
135    public boolean isValidSyntax( Object value )
136    {
137        String strValue = null;
138
139        if ( value == null )
140        {
141            LOG.debug( "Syntax invalid for 'null'" );
142            return false;
143        }
144
145        if ( value instanceof String )
146        {
147            strValue = ( String ) value;
148        }
149        else if ( value instanceof byte[] )
150        {
151            strValue = Strings.utf8ToString( ( byte[] ) value );
152        }
153        else
154        {
155            strValue = value.toString();
156        }
157
158        if ( strValue.length() == 0 )
159        {
160            LOG.debug( "Syntax invalid for '{}'", value );
161            return false;
162        }
163
164        // We will use a regexp to check the TelephoneNumber.
165        if ( defaultMandatory )
166        {
167            // We have a unique regexp to check, the default one
168            boolean result = defaultPattern.matcher( strValue ).matches();
169
170            if ( result )
171            {
172                LOG.debug( "Syntax valid for '{}'", value );
173            }
174            else
175            {
176                LOG.debug( "Syntax invalid for '{}'", value );
177            }
178
179            return result;
180        }
181        else
182        {
183            if ( defaultPattern.matcher( strValue ).matches() )
184            {
185                LOG.debug( "Syntax valid for '{}'", value );
186                return true;
187            }
188            else
189            {
190                if ( compiledREs == null )
191                {
192                    LOG.debug( "Syntax invalid for '{}'", value );
193                    return false;
194                }
195
196                // The default is not enough, let's try
197                // the other regexps
198                for ( Pattern pattern : compiledREs )
199                {
200                    if ( pattern.matcher( strValue ).matches() )
201                    {
202                        LOG.debug( "Syntax valid for '{}'", value );
203                        return true;
204                    }
205                }
206
207                LOG.debug( "Syntax invalid for '{}'", value );
208                return false;
209            }
210        }
211    }
212}