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     */
020    package org.apache.directory.shared.ldap.schema.syntaxes;
021    
022    
023    import java.util.HashSet;
024    import java.util.Set;
025    
026    import org.apache.directory.shared.ldap.constants.SchemaConstants;
027    import org.apache.directory.shared.ldap.schema.AbstractSyntaxChecker;
028    import org.apache.directory.shared.ldap.util.StringTools;
029    
030    
031    /**
032     * A SyntaxChecker which verifies that a value is a DSEType according to 
033     * http://tools.ietf.org/id/draft-ietf-asid-ldapv3-attributes-03.txt, par 6.2.1.5 :
034     * 
035     * <DSEType>    ::= '(' <sp>* <DSEBit> <sp>* <DSEBitList> ')'
036     * <DSEBitList> ::= '$' <sp>* <DSEBit> <sp>* <DSEBitList> | e      
037     * <DSEBit>     ::= 'root' | 'glue' | 'cp' | 'entry' | 'alias' | 'subr' |
038     *                  'nssr' | 'supr' | 'xr' | 'admPoint' | 'subentry' |
039     *                  'shadow' | 'zombie' | 'immSupr' | 'rhob' | 'sa'
040     * 
041     *
042     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
043     * @version $Rev$
044     */
045    public class DSETypeSyntaxChecker extends AbstractSyntaxChecker
046    {
047        /** The DSE BITS keywords */
048        private static final String[] DSE_BITS_STRINGS = 
049            {
050            "root", "glue", "cp", "entry", "alias", "subr",
051            "nssr", "supr", "xr", "admPoint", "subentry",
052            "shadow", "zombie", "immSupr", "rhob", "sa"
053            };
054        
055        
056        /** The Set which contains the DESBits */
057        private static final Set<String> DSE_BITS = new HashSet<String>();
058        
059        /** Initialization of the country set */
060        static
061        {
062            for ( String country:DSE_BITS_STRINGS )
063            {
064                DSE_BITS.add( country );
065            }
066        }
067    
068        
069        /**
070         * 
071         * Creates a new instance of DSETypeSyntaxChecker.
072         *
073         */
074        public DSETypeSyntaxChecker()
075        {
076            super( SchemaConstants.DSE_TYPE_SYNTAX );
077        }
078        
079        /**
080         * 
081         * Creates a new instance of DSETypeSyntaxChecker.
082         * 
083         * @param oid the oid to associate with this new SyntaxChecker
084         *
085         */
086        protected DSETypeSyntaxChecker( String oid )
087        {
088            super( oid );
089        }
090        
091        
092        /* (non-Javadoc)
093         * @see org.apache.directory.shared.ldap.schema.SyntaxChecker#isValidSyntax(java.lang.Object)
094         */
095        public boolean isValidSyntax( Object value )
096        {
097            String strValue = null;
098    
099            if ( value == null )
100            {
101                return false;
102            }
103            
104            if ( value instanceof String )
105            {
106                strValue = ( String ) value;
107            }
108            else if ( value instanceof byte[] )
109            {
110                strValue = StringTools.utf8ToString( ( byte[] ) value ); 
111            }
112            else
113            {
114                strValue = value.toString();
115            }
116    
117            // We must have at least '(cp)', '(xr)' or '(ca)'
118            if ( strValue.length() < 4 )
119            {
120                return false;
121            }
122    
123            // Check the opening and closing parenthesis
124            if ( ( strValue.charAt( 0 ) != '(' ) || 
125                 ( strValue.charAt( strValue.length() - 1 ) != ')' ) )
126            {
127                return false;
128            }
129    
130            Set<String> keywords = new HashSet<String>();
131            int len = strValue.length() - 1;
132            boolean needKeyword = true;
133            
134            // 
135            for ( int i = 1; i < len; /* */ )
136            {
137                // Skip spaces
138                while ( ( i < len ) && ( strValue.charAt( i ) == ' ' ) )
139                {
140                    i++;
141                }
142                
143                int pos = i;
144                
145                // Search for a keyword
146                while ( ( i < len ) && StringTools.isAlphaASCII( strValue, pos ) )
147                {
148                    pos++;
149                }
150                
151                if ( pos == i )
152                {
153                    // No keyword : error
154                    return false;
155                }
156                
157                String keyword = strValue.substring( i, pos );
158                i = pos;
159                
160                if ( !DSE_BITS.contains( keyword ) )
161                {
162                    // Unkown keyword
163                    return false;
164                }
165                
166                // Check that the keyword has not been met
167                if ( keywords.contains( keyword ) )
168                {
169                    return false;
170                }
171                
172                keywords.add( keyword );
173                needKeyword = false;
174                
175                // Skip spaces
176                while ( ( i < len ) && ( strValue.charAt( i ) == ' ' ) )
177                {
178                    i++;
179                }
180                
181                // Do we have another keyword ?
182                if ( ( i < len) && ( strValue.charAt( i ) == '$' ) )
183                {
184                    // yes
185                    i++;
186                    needKeyword = true;
187                    continue;
188                }
189            }
190            
191            // We are done
192            return !needKeyword;
193        }
194    }