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   *    http://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      /** Speedup for logs */
57      static final boolean IS_DEBUG = LOG.isDebugEnabled();
58  
59      /** The instance of grammar. PagedSearchControlGrammar is a singleton */
60      private static Grammar<?> instance = new PagedResultsGrammar();
61  
62  
63      /**
64       * Creates a new PagedSearchControlGrammar object.
65       */
66      @SuppressWarnings("unchecked")
67      private PagedResultsGrammar()
68      {
69          setName( PagedResultsGrammar.class.getName() );
70  
71          // Create the transitions table
72          super.transitions = new GrammarTransition[PagedResultsStates.LAST_PAGED_SEARCH_STATE.ordinal()][256];
73  
74          /** 
75           * Transition from initial state to PagedSearch sequence
76           * realSearchControlValue ::= SEQUENCE OF {
77           *     ...
78           *     
79           * Nothing to do
80           */
81          super.transitions[PagedResultsStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
82              new GrammarTransition<PagedResultsContainer>( PagedResultsStates.START_STATE,
83                  PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
84                  UniversalTag.SEQUENCE.getValue(), null );
85  
86          /** 
87           * Transition from PagedSearch sequence to size
88           * 
89           * realSearchControlValue ::= SEQUENCE OF {
90           *     size  INTEGER,  -- INTEGER (0..maxInt),
91           *     ...
92           *     
93           * Stores the size value
94           */
95          super.transitions[PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
96              new GrammarTransition<PagedResultsContainer>( PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
97                  PagedResultsStates.SIZE_STATE,
98                  UniversalTag.INTEGER.getValue(),
99                  new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl size" )
100                 {
101                     public void action( PagedResultsContainer container ) throws DecoderException
102                     {
103                         BerValue value = container.getCurrentTLV().getValue();
104 
105                         try
106                         {
107                             // Check that the value is into the allowed interval
108                             int size = IntegerDecoder.parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE );
109 
110                             // We allow negative value to absorb a bug in some M$ client.
111                             // Those negative values will be transformed to Integer.MAX_VALUE.
112                             if ( size < 0 )
113                             {
114                                 size = Integer.MAX_VALUE;
115                             }
116 
117                             if ( IS_DEBUG )
118                             {
119                                 LOG.debug( "size = " + size );
120                             }
121 
122                             container.getDecorator().setSize( size );
123                         }
124                         catch ( IntegerDecoderException ide )
125                         {
126                             String msg = I18n.err( I18n.ERR_04050 );
127                             LOG.error( msg, ide );
128                             throw new DecoderException( msg, ide );
129                         }
130                     }
131                 } );
132 
133         /** 
134          * Transition from size to cookie
135          * realSearchControlValue ::= SEQUENCE OF {
136          *     ...
137          *     cookie   OCTET STRING
138          * }
139          *     
140          * Stores the cookie flag
141          */
142         super.transitions[PagedResultsStates.SIZE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
143             new GrammarTransition<PagedResultsContainer>( PagedResultsStates.SIZE_STATE,
144                 PagedResultsStates.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
145                 new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl cookie" )
146                 {
147                     public void action( PagedResultsContainer container ) throws DecoderException
148                     {
149                         BerValue value = container.getCurrentTLV().getValue();
150 
151                         if ( container.getCurrentTLV().getLength() == 0 )
152                         {
153                             container.getDecorator().setCookie( Strings.EMPTY_BYTES );
154                         }
155                         else
156                         {
157                             container.getDecorator().setCookie( value.getData() );
158                         }
159 
160                         // We can have an END transition
161                         container.setGrammarEndAllowed( true );
162                     }
163                 } );
164     }
165 
166 
167     /**
168      * This class is a singleton.
169      * 
170      * @return An instance on this grammar
171      */
172     public static Grammar<?> getInstance()
173     {
174         return instance;
175     }
176 }