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 org.apache.directory.api.asn1.util.Oid;
024import org.apache.directory.api.i18n.I18n;
025import org.apache.directory.api.ldap.model.constants.SchemaConstants;
026import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
027import org.apache.directory.api.util.Chars;
028import org.apache.directory.api.util.Strings;
029
030
031/**
032 * A SyntaxChecker which verifies that a value is an oid according to RFC 4512.
033 * <p>
034 * From RFC 4512 :
035 * <pre>
036 * oid = descr | numericoid
037 * descr = keystring
038 * keystring = leadkeychar *keychar
039 * leadkeychar = ALPHA
040 * keychar = ALPHA | DIGIT | HYPHEN
041 * number  = DIGIT | ( LDIGIT 1*DIGIT )
042 * ALPHA   = %x41-5A | %x61-7A              ; "A"-"Z" | "a"-"z"
043 * DIGIT   = %x30 | LDIGIT                  ; "0"-"9"
044 * LDIGIT  = %x31-39                        ; "1"-"9"
045 * HYPHEN  = %x2D                           ; hyphen ("-")
046 * numericoid = number 1*( DOT number )
047 * DOT     = %x2E                           ; period (".")
048 * </pre>
049 *
050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051 */
052@SuppressWarnings("serial")
053public final class OidSyntaxChecker extends SyntaxChecker
054{
055    /**
056     * A static instance of OidSyntaxChecker
057     */
058    public static final OidSyntaxChecker INSTANCE = new OidSyntaxChecker( SchemaConstants.OID_SYNTAX );
059    
060    /**
061     * A static Builder for this class
062     */
063    public static final class Builder extends SCBuilder<OidSyntaxChecker>
064    {
065        /**
066         * The Builder constructor
067         */
068        private Builder()
069        {
070            super( SchemaConstants.OID_SYNTAX );
071        }
072        
073        
074        /**
075         * Create a new instance of OidSyntaxChecker
076         * @return A new instance of OidSyntaxChecker
077         */
078        @Override
079        public OidSyntaxChecker build()
080        {
081            return new OidSyntaxChecker( oid );
082        }
083    }
084
085    
086    /**
087     * Creates a new instance of OidSyntaxChecker.
088     * 
089     * @param oid The OID to use for this SyntaxChecker
090     */
091    private OidSyntaxChecker( String oid )
092    {
093        super( oid );
094    }
095
096    
097    /**
098     * @return An instance of the Builder for this class
099     */
100    public static Builder builder()
101    {
102        return new Builder();
103    }
104
105
106    /**
107     * {@inheritDoc}
108     */
109    @Override
110    public boolean isValidSyntax( Object value )
111    {
112        String strValue;
113
114        if ( value == null )
115        {
116            if ( LOG.isDebugEnabled() )
117            {
118                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) );
119            }
120            
121            return false;
122        }
123
124        if ( value instanceof String )
125        {
126            strValue = ( String ) value;
127        }
128        else if ( value instanceof byte[] )
129        {
130            strValue = Strings.utf8ToString( ( byte[] ) value );
131        }
132        else
133        {
134            strValue = value.toString();
135        }
136
137        if ( strValue.length() == 0 )
138        {
139            if ( LOG.isDebugEnabled() )
140            {
141                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
142            }
143            
144            return false;
145        }
146
147        // if the first character is a digit it's an attempt at an OID and must be
148        // checked to make sure there are no other chars except '.' and digits.
149        if ( Chars.isDigit( strValue.charAt( 0 ) ) )
150        {
151            boolean result = Oid.isOid(  strValue  );
152            
153            if ( LOG.isDebugEnabled() )
154            {
155                if ( result )
156                {
157                    LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
158                }
159                else
160                {
161                    LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
162                }
163            }
164            
165            return result;
166        }
167
168        // here we just need to make sure that we have the right characters in the 
169        // string and that it starts with a letter.
170        if ( Chars.isAlphaASCII( strValue, 0 ) )
171        {
172            for ( int index = 0; index < strValue.length(); index++ )
173            {
174                char c = strValue.charAt( index );
175                
176                if ( !Chars.isAlphaDigitMinus( c ) )
177                {
178                    if ( LOG.isDebugEnabled() )
179                    {
180                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
181                    }
182                    
183                    return false;
184                }
185            }
186
187            if ( LOG.isDebugEnabled() )
188            {
189                LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
190            }
191            
192            return true;
193        }
194        else
195        {
196            if ( LOG.isDebugEnabled() )
197            {
198                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
199            }
200            
201            return false;
202        }
203    }
204}