View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.codec.controls.search.pagedSearch;
21  
22  
23  import org.apache.directory.api.asn1.DecoderException;
24  import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
25  import org.apache.directory.api.asn1.ber.grammar.Grammar;
26  import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
27  import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
28  import org.apache.directory.api.asn1.ber.tlv.BerValue;
29  import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
30  import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.util.Strings;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  
38  /**
39   * This class implements the PagedSearchControl. All the actions are declared in
40   * this class. As it is a singleton, these declaration are only done once.
41   * 
42   * The decoded grammar is the following :
43   * 
44   * realSearchControlValue ::= SEQUENCE {
45   *     size   INTEGER,
46   *     cookie OCTET STRING,
47   * }
48   * 
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  public final class PagedResultsGrammar extends AbstractGrammar<PagedResultsContainer>
52  {
53      /** The logger */
54      static final Logger LOG = LoggerFactory.getLogger( PagedResultsGrammar.class );
55  
56      /** The instance of grammar. PagedSearchControlGrammar is a singleton */
57      private static Grammar<?> instance = new PagedResultsGrammar();
58  
59  
60      /**
61       * Creates a new PagedSearchControlGrammar object.
62       */
63      @SuppressWarnings("unchecked")
64      private PagedResultsGrammar()
65      {
66          setName( PagedResultsGrammar.class.getName() );
67  
68          // Create the transitions table
69          super.transitions = new GrammarTransition[PagedResultsStates.LAST_PAGED_SEARCH_STATE.ordinal()][256];
70  
71          /** 
72           * Transition from initial state to PagedSearch sequence
73           * realSearchControlValue ::= SEQUENCE OF {
74           *     ...
75           *     
76           * Nothing to do
77           */
78          super.transitions[PagedResultsStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
79              new GrammarTransition<PagedResultsContainer>( PagedResultsStates.START_STATE,
80                  PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
81                  UniversalTag.SEQUENCE.getValue(), null );
82  
83          /** 
84           * Transition from PagedSearch sequence to size
85           * 
86           * realSearchControlValue ::= SEQUENCE OF {
87           *     size  INTEGER,  -- INTEGER (0..maxInt),
88           *     ...
89           *     
90           * Stores the size value
91           */
92          super.transitions[PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
93              new GrammarTransition<PagedResultsContainer>( PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
94                  PagedResultsStates.SIZE_STATE,
95                  UniversalTag.INTEGER.getValue(),
96                  new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl size" )
97                  {
98                      public void action( PagedResultsContainer container ) throws DecoderException
99                      {
100                         BerValue value = container.getCurrentTLV().getValue();
101 
102                         try
103                         {
104                             // Check that the value is into the allowed interval
105                             int size = IntegerDecoder.parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE );
106 
107                             // We allow negative value to absorb a bug in some M$ client.
108                             // Those negative values will be transformed to Integer.MAX_VALUE.
109                             if ( size < 0 )
110                             {
111                                 size = Integer.MAX_VALUE;
112                             }
113 
114                             if ( LOG.isDebugEnabled() )
115                             {
116                                 LOG.debug( I18n.msg( I18n.MSG_05303_SIZE, size ) );
117                             }
118 
119                             container.getPagedResults().setSize( size );
120                         }
121                         catch ( IntegerDecoderException ide )
122                         {
123                             String msg = I18n.err( I18n.ERR_05306_PAGED_SEARCH_SIZE_DECODING_ERROR );
124                             LOG.error( msg, ide );
125                             throw new DecoderException( msg, ide );
126                         }
127                     }
128                 } );
129 
130         /** 
131          * Transition from size to cookie
132          * realSearchControlValue ::= SEQUENCE OF {
133          *     ...
134          *     cookie   OCTET STRING
135          * }
136          *     
137          * Stores the cookie flag
138          */
139         super.transitions[PagedResultsStates.SIZE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
140             new GrammarTransition<PagedResultsContainer>( PagedResultsStates.SIZE_STATE,
141                 PagedResultsStates.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
142                 new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl cookie" )
143                 {
144                     public void action( PagedResultsContainer container )
145                     {
146                         BerValue value = container.getCurrentTLV().getValue();
147 
148                         if ( container.getCurrentTLV().getLength() == 0 )
149                         {
150                             container.getPagedResults().setCookie( Strings.EMPTY_BYTES );
151                         }
152                         else
153                         {
154                             container.getPagedResults().setCookie( value.getData() );
155                         }
156 
157                         // We can have an END transition
158                         container.setGrammarEndAllowed( true );
159                     }
160                 } );
161     }
162 
163 
164     /**
165      * This class is a singleton.
166      * 
167      * @return An instance on this grammar
168      */
169     public static Grammar<?> getInstance()
170     {
171         return instance;
172     }
173 }