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.ldap.model.schema.SyntaxChecker;
028import org.apache.directory.api.util.Chars;
029import org.apache.directory.api.util.Strings;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033
034/**
035 * A SyntaxChecker which verifies that a value is a delivery method 
036 * according to RFC 4517.
037 * 
038 * From RFC 4517 & RFC 4512:
039 * 
040 * DeliveryMethod = pdm *( WSP DOLLAR WSP pdm )
041 *
042 * pdm = "any" | "mhs" | "physical" | "telex" | "teletex" |
043 *       "g3fax" | "g4fax" | "ia5" | "videotex" | "telephone"
044 *           
045 * WSP     = 0*SPACE  ; zero or more " "
046 * DOLLAR  = %x24 ; dollar sign ("$")
047 * SPACE   = %x20 ; space (" ")
048 * 
049 *
050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051 */
052@SuppressWarnings("serial")
053public class DeliveryMethodSyntaxChecker extends SyntaxChecker
054{
055    /** A logger for this class */
056    private static final Logger LOG = LoggerFactory.getLogger( DeliveryMethodSyntaxChecker.class );
057
058    private static final String[] PDMS =
059        {
060            "any", "mhs", "physical", "telex", "teletex",
061            "g3fax", "g4fax", "ia5", "videotex", "telephone"
062    };
063
064    /** The Set which contains the delivery methods */
065    private static final Set<String> DELIVERY_METHODS = new HashSet<String>();
066
067    /** Initialization of the delivery methods set */
068    static
069    {
070        for ( String country : PDMS )
071        {
072            DELIVERY_METHODS.add( country );
073        }
074    }
075
076
077    /**
078     * 
079     * Creates a new instance of DeliveryMethodSyntaxChecker.
080     *
081     */
082    public DeliveryMethodSyntaxChecker()
083    {
084        super( SchemaConstants.DELIVERY_METHOD_SYNTAX );
085    }
086
087
088    /**
089     * 
090     * Check if the string contains a delivery method which has 
091     * not already been found.
092     * 
093     * @param strValue The string we want to look into for a PDM 
094     * @param pos The current position in the string
095     * @param pdms The set containing all the PDM
096     * @return if a Prefered Delivery Method is found in the given string, returns 
097     * its position, otherwise, returns -1
098     */
099    private int isPdm( String strValue, int start, Set<String> pdms )
100    {
101        int pos = start;
102
103        while ( Chars.isAlphaDigit( strValue, pos ) )
104        {
105            pos++;
106        }
107
108        // No ascii string, this is not a delivery method
109        if ( pos == start )
110        {
111            return -1;
112        }
113
114        String pdm = strValue.substring( start, pos );
115
116        if ( !DELIVERY_METHODS.contains( pdm ) )
117        {
118            // The delivery method is unknown
119            return -1;
120        }
121        else
122        {
123            if ( pdms.contains( pdm ) )
124            {
125                // The delivery method has already been found
126                return -1;
127            }
128            else
129            {
130                pdms.add( pdm );
131                return pos;
132            }
133        }
134    }
135
136
137    /**
138     * {@inheritDoc}
139     */
140    public boolean isValidSyntax( Object value )
141    {
142        String strValue = null;
143
144        if ( value == null )
145        {
146            LOG.debug( "Syntax invalid for 'null'" );
147            return false;
148        }
149
150        if ( value instanceof String )
151        {
152            strValue = ( String ) value;
153        }
154        else if ( value instanceof byte[] )
155        {
156            strValue = Strings.utf8ToString( ( byte[] ) value );
157        }
158        else
159        {
160            strValue = value.toString();
161        }
162
163        if ( strValue.length() == 0 )
164        {
165            LOG.debug( "Syntax invalid for '{}'", value );
166            return false;
167        }
168
169        // We will get the first delivery method
170        int length = strValue.length();
171        int pos = 0;
172        Set<String> pmds = new HashSet<String>();
173
174        if ( ( pos = isPdm( strValue, pos, pmds ) ) == -1 )
175        {
176            LOG.debug( "Syntax invalid for '{}'", value );
177            return false;
178        }
179
180        // We have found at least the first pmd,
181        // now iterate through the other ones. We may have
182        // SP* '$' SP* before each pmd.
183        while ( pos < length )
184        {
185            // Skip spaces
186            while ( Strings.isCharASCII( strValue, pos, ' ' ) )
187            {
188                pos++;
189            }
190
191            if ( !Strings.isCharASCII( strValue, pos, '$' ) )
192            {
193                // A '$' was expected
194                LOG.debug( "Syntax invalid for '{}'", value );
195                return false;
196            }
197            else
198            {
199                pos++;
200            }
201
202            // Skip spaces
203            while ( Strings.isCharASCII( strValue, pos, ' ' ) )
204            {
205                pos++;
206            }
207
208            if ( ( pos = isPdm( strValue, pos, pmds ) ) == -1 )
209            {
210                LOG.debug( "Syntax invalid for '{}'", value );
211                return false;
212            }
213        }
214
215        LOG.debug( "Syntax valid for '{}'", value );
216        return true;
217    }
218}