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.i18n.I18n;
024import org.apache.directory.api.ldap.model.constants.SchemaConstants;
025import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
026import org.apache.directory.api.util.Strings;
027
028
029/**
030 * A SyntaxChecker which verifies that a value is a DSAQualitySyntax according to 
031 * http://tools.ietf.org/id/draft-ietf-asid-ldapv3-attributes-03.txt, par 5.2.2.2 :
032 * <pre>
033 * &lt;DsaQualitySyntax&gt; ::= &lt;DSAKeyword&gt; [ '#' &lt;description&gt; ]
034 *
035 * &lt;DSAKeyword&gt; ::= 'DEFUNCT' | 'EXPERIMENTAL' | 'BEST-EFFORT' |
036 *                  'PILOT-SERVICE' | 'FULL-SERVICE'
037 *
038 * &lt;description&gt; ::= encoded as a PrintableString
039 * </pre>
040 *
041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042 */
043@SuppressWarnings("serial")
044public final class DsaQualitySyntaxSyntaxChecker extends SyntaxChecker
045{
046    /**
047     * A static instance of DsaQualitySyntaxSyntaxChecker
048     */
049    public static final DsaQualitySyntaxSyntaxChecker INSTANCE = 
050        new DsaQualitySyntaxSyntaxChecker( SchemaConstants.DSA_QUALITY_SYNTAX );
051    
052    /**
053     * A static Builder for this class
054     */
055    public static final class Builder extends SCBuilder<DsaQualitySyntaxSyntaxChecker>
056    {
057        /**
058         * The Builder constructor
059         */
060        private Builder()
061        {
062            super( SchemaConstants.DSA_QUALITY_SYNTAX );
063        }
064        
065        
066        /**
067         * Create a new instance of DsaQualitySyntaxSyntaxChecker
068         * @return A new instance of DsaQualitySyntaxSyntaxChecker
069         */
070        @Override
071        public DsaQualitySyntaxSyntaxChecker build()
072        {
073            return new DsaQualitySyntaxSyntaxChecker( oid );
074        }
075    }
076
077    
078    /**
079     * Creates a new instance of DSAQualitySyntaxSyntaxChecker.
080     * 
081     * @param oid The OID to use for this SyntaxChecker
082     */
083    private DsaQualitySyntaxSyntaxChecker( String oid )
084    {
085        super( oid );
086    }
087
088    
089    /**
090     * @return An instance of the Builder for this class
091     */
092    public static Builder builder()
093    {
094        return new Builder();
095    }
096
097
098    /**
099     * {@inheritDoc}
100     */
101    @Override
102    public boolean isValidSyntax( Object value )
103    {
104        String strValue;
105
106        if ( value == null )
107        {
108            if ( LOG.isDebugEnabled() )
109            {
110                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) );
111            }
112            
113            return false;
114        }
115
116        if ( value instanceof String )
117        {
118            strValue = ( String ) value;
119        }
120        else if ( value instanceof byte[] )
121        {
122            strValue = Strings.utf8ToString( ( byte[] ) value );
123        }
124        else
125        {
126            strValue = value.toString();
127        }
128
129        if ( strValue.length() < 7 )
130        {
131            if ( LOG.isDebugEnabled() )
132            {
133                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
134            }
135            
136            return false;
137        }
138
139        String remaining;
140
141        switch ( strValue.charAt( 0 ) )
142        {
143            case 'B':
144                if ( !strValue.startsWith( "BEST-EFFORT" ) )
145                {
146                    if ( LOG.isDebugEnabled() )
147                    {
148                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
149                    }
150                    
151                    return false;
152                }
153
154                remaining = strValue.substring( "BEST-EFFORT".length() );
155                break;
156
157            case 'D':
158                if ( !strValue.startsWith( "DEFUNCT" ) )
159                {
160                    if ( LOG.isDebugEnabled() )
161                    {
162                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
163                    }
164                    
165                    return false;
166                }
167
168                remaining = strValue.substring( "DEFUNCT".length() );
169                break;
170
171            case 'E':
172                if ( !strValue.startsWith( "EXPERIMENTAL" ) )
173                {
174                    if ( LOG.isDebugEnabled() )
175                    {
176                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
177                    }
178                    
179                    return false;
180                }
181
182                remaining = strValue.substring( "EXPERIMENTAL".length() );
183                break;
184
185            case 'F':
186                if ( !strValue.startsWith( "FULL-SERVICE" ) )
187                {
188                    if ( LOG.isDebugEnabled() )
189                    {
190                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
191                    }
192                    
193                    return false;
194                }
195
196                remaining = strValue.substring( "FULL-SERVICE".length() );
197                break;
198
199            case 'P':
200                if ( !strValue.startsWith( "PILOT-SERVICE" ) )
201                {
202                    if ( LOG.isDebugEnabled() )
203                    {
204                        LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
205                    }
206                    
207                    return false;
208                }
209
210                remaining = strValue.substring( "PILOT-SERVICE".length() );
211                break;
212
213            default:
214                if ( LOG.isDebugEnabled() )
215                {
216                    LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
217                }
218                
219                return false;
220        }
221
222        // Now, we might have a description separated from the keyword by a '#'
223        // but this is optional
224        if ( remaining.length() == 0 )
225        {
226            if ( LOG.isDebugEnabled() )
227            {
228                LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
229            }
230            
231            return true;
232        }
233
234        if ( remaining.charAt( 0 ) != '#' )
235        {
236            // We were expecting a '#'
237            if ( LOG.isDebugEnabled() )
238            {
239                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
240            }
241            
242            return false;
243        }
244
245        // Check that the description is a PrintableString
246        boolean result = Strings.isPrintableString( remaining.substring( 1 ) );
247
248        if ( LOG.isDebugEnabled() )
249        {
250            if ( result )
251            {
252                LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) );
253            }
254            else
255            {
256                LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) );
257            }
258        }
259
260        return result;
261    }
262}