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.codec.controls.sort;
021
022
023import static org.apache.directory.api.ldap.codec.controls.sort.SortRequestDecorator.ORDERING_RULE_TAG;
024import static org.apache.directory.api.ldap.codec.controls.sort.SortRequestDecorator.REVERSE_ORDER_TAG;
025
026import org.apache.directory.api.asn1.DecoderException;
027import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
028import org.apache.directory.api.asn1.ber.grammar.Grammar;
029import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
030import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
031import org.apache.directory.api.asn1.ber.tlv.BerValue;
032import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
033import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
034import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
035import org.apache.directory.api.ldap.model.message.controls.SortKey;
036import org.apache.directory.api.util.Strings;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * Grammar used for decoding a SortRequestControl. It's defined in https://tools.ietf.org/html/rfc2891
043 * 
044 * <pre>
045 * SortKeyList ::= SEQUENCE OF SEQUENCE {
046 *               attributeType   AttributeDescription,
047 *               orderingRule    [0] MatchingRuleId OPTIONAL,
048 *               reverseOrder    [1] BOOLEAN DEFAULT FALSE }
049 * </pre>
050 *
051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052 */
053public final class SortRequestGrammar extends AbstractGrammar<SortRequestContainer>
054{
055    /** The logger */
056    static final Logger LOG = LoggerFactory.getLogger( SortRequestGrammar.class );
057
058    /** Speedup for logs */
059    static final boolean IS_DEBUG = LOG.isDebugEnabled();
060
061    /** The instance of grammar. SortRequestGrammar is a singleton */
062    private static Grammar<SortRequestContainer> instance = new SortRequestGrammar();
063
064
065    @SuppressWarnings("unchecked")
066    private SortRequestGrammar()
067    {
068        setName( SortRequestGrammar.class.getName() );
069
070        GrammarAction<SortRequestContainer> addSortKey = new GrammarAction<SortRequestContainer>()
071        {
072
073            @Override
074            public void action( SortRequestContainer container ) throws DecoderException
075            {
076                BerValue value = container.getCurrentTLV().getValue();
077
078                String atDesc = Strings.utf8ToString( value.getData() );
079                if ( IS_DEBUG )
080                {
081                    LOG.debug( "AttributeTypeDesc = " + atDesc );
082                }
083
084                SortKey sk = new SortKey( atDesc );
085                container.setCurrentKey( sk );
086                container.getControl().addSortKey( sk );
087                container.setGrammarEndAllowed( true );
088            }
089
090        };
091
092        GrammarAction<SortRequestContainer> storeReverseOrder = new GrammarAction<SortRequestContainer>()
093        {
094
095            @Override
096            public void action( SortRequestContainer container ) throws DecoderException
097            {
098                BerValue value = container.getCurrentTLV().getValue();
099
100                try
101                {
102                    boolean reverseOrder = BooleanDecoder.parse( value );
103
104                    if ( IS_DEBUG )
105                    {
106                        LOG.debug( "ReverseOrder = " + reverseOrder );
107                    }
108
109                    container.getCurrentKey().setReverseOrder( reverseOrder );
110
111                    container.setGrammarEndAllowed( true );
112                }
113                catch ( BooleanDecoderException bde )
114                {
115                    throw new DecoderException( bde.getMessage(), bde );
116                }
117            }
118
119        };
120
121        // Create the transitions table
122        super.transitions = new GrammarTransition[SortRequestStates.END_STATE.ordinal()][256];
123
124        super.transitions[SortRequestStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
125            new GrammarTransition<SortRequestContainer>( SortRequestStates.START_STATE,
126                SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE,
127                UniversalTag.SEQUENCE.getValue(), null );
128
129        super.transitions[SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
130            new GrammarTransition<SortRequestContainer>( SortRequestStates.SEQUENCE_OF_SEQUENCE_STATE,
131                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
132                UniversalTag.SEQUENCE.getValue(), null );
133
134        super.transitions[SortRequestStates.SORT_KEY_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
135            new GrammarTransition<SortRequestContainer>( SortRequestStates.SORT_KEY_SEQUENCE_STATE,
136                SortRequestStates.AT_DESC_STATE,
137                UniversalTag.OCTET_STRING.getValue(), addSortKey );
138
139        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][ORDERING_RULE_TAG] =
140            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
141                SortRequestStates.ORDER_RULE_STATE,
142                ORDERING_RULE_TAG, new GrammarAction<SortRequestContainer>()
143                {
144
145                    @Override
146                    public void action( SortRequestContainer container ) throws DecoderException
147                    {
148                        BerValue value = container.getCurrentTLV().getValue();
149
150                        String matchingRuleOid = Strings.utf8ToString( value.getData() );
151
152                        if ( IS_DEBUG )
153                        {
154                            LOG.debug( "MatchingRuleOid = " + matchingRuleOid );
155                        }
156
157                        container.getCurrentKey().setMatchingRuleId( matchingRuleOid );
158                        container.setGrammarEndAllowed( true );
159                    }
160
161                } );
162
163        super.transitions[SortRequestStates.ORDER_RULE_STATE.ordinal()][REVERSE_ORDER_TAG] =
164            new GrammarTransition<SortRequestContainer>( SortRequestStates.ORDER_RULE_STATE,
165                SortRequestStates.REVERSE_ORDER_STATE,
166                REVERSE_ORDER_TAG, storeReverseOrder );
167
168        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][REVERSE_ORDER_TAG] =
169            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
170                SortRequestStates.REVERSE_ORDER_STATE,
171                REVERSE_ORDER_TAG, storeReverseOrder );
172
173        super.transitions[SortRequestStates.REVERSE_ORDER_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
174            new GrammarTransition<SortRequestContainer>( SortRequestStates.REVERSE_ORDER_STATE,
175                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
176                UniversalTag.SEQUENCE.getValue(), null );
177
178        super.transitions[SortRequestStates.AT_DESC_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
179            new GrammarTransition<SortRequestContainer>( SortRequestStates.AT_DESC_STATE,
180                SortRequestStates.SORT_KEY_SEQUENCE_STATE,
181                UniversalTag.SEQUENCE.getValue(), null );
182
183    }
184
185
186    /**
187     * This class is a singleton.
188     * 
189     * @return An instance on this grammar
190     */
191    public static Grammar<?> getInstance()
192    {
193        return instance;
194    }
195}