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 */
020 package org.apache.directory.shared.ldap.codec.search.controls.pagedSearch;
021
022
023 import org.apache.directory.shared.asn1.ber.IAsn1Container;
024 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
025 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
026 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
027 import org.apache.directory.shared.asn1.ber.grammar.IGrammar;
028 import org.apache.directory.shared.asn1.ber.grammar.IStates;
029 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030 import org.apache.directory.shared.asn1.ber.tlv.Value;
031 import org.apache.directory.shared.asn1.codec.DecoderException;
032 import org.apache.directory.shared.asn1.util.IntegerDecoder;
033 import org.apache.directory.shared.asn1.util.IntegerDecoderException;
034 import org.apache.directory.shared.ldap.util.StringTools;
035 import org.slf4j.Logger;
036 import org.slf4j.LoggerFactory;
037
038
039 /**
040 * This class implements the PagedSearchControl. All the actions are declared in
041 * this class. As it is a singleton, these declaration are only done once.
042 *
043 * The decoded grammar is the following :
044 *
045 * realSearchControlValue ::= SEQUENCE {
046 * size INTEGER,
047 * cookie OCTET STRING,
048 * }
049 *
050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051 * @version $Rev: 664290 $, $Date: 2008-06-07 08:28:06 +0200 (Sat, 07 Jun 2008) $,
052 */
053 public class PagedSearchControlGrammar extends AbstractGrammar
054 {
055 /** The logger */
056 static final Logger log = LoggerFactory.getLogger( PagedSearchControlGrammar.class );
057
058 /** Speedup for logs */
059 static final boolean IS_DEBUG = log.isDebugEnabled();
060
061 /** The instance of grammar. PagedSearchControlGrammar is a singleton */
062 private static IGrammar instance = new PagedSearchControlGrammar();
063
064
065 /**
066 * Creates a new PagedSearchControlGrammar object.
067 */
068 private PagedSearchControlGrammar()
069 {
070 name = PagedSearchControlGrammar.class.getName();
071 statesEnum = PagedSearchControlStatesEnum.getInstance();
072
073 // Create the transitions table
074 super.transitions = new GrammarTransition[PagedSearchControlStatesEnum.LAST_PAGED_SEARCH_STATE][256];
075
076 /**
077 * Transition from initial state to PagedSearch sequence
078 * realSearchControlValue ::= SEQUENCE OF {
079 * ...
080 *
081 * Initialize the persistence search object
082 */
083 super.transitions[IStates.INIT_GRAMMAR_STATE][UniversalTag.SEQUENCE_TAG] =
084 new GrammarTransition( IStates.INIT_GRAMMAR_STATE,
085 PagedSearchControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE,
086 UniversalTag.SEQUENCE_TAG,
087 new GrammarAction( "Init PagedSearchControl" )
088 {
089 public void action( IAsn1Container container )
090 {
091 PagedSearchControlContainer pagedSearchContainer = ( PagedSearchControlContainer ) container;
092 PagedSearchControlCodec control = new PagedSearchControlCodec();
093 pagedSearchContainer.setPagedSearchControl( control );
094 }
095 } );
096
097
098 /**
099 * Transition from PagedSearch sequence to size
100 *
101 * realSearchControlValue ::= SEQUENCE OF {
102 * size INTEGER, -- INTEGER (0..maxInt),
103 * ...
104 *
105 * Stores the size value
106 */
107 super.transitions[PagedSearchControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE][UniversalTag.INTEGER_TAG] =
108 new GrammarTransition( PagedSearchControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE,
109 PagedSearchControlStatesEnum.SIZE_STATE,
110 UniversalTag.INTEGER_TAG,
111 new GrammarAction( "Set PagedSearchControl size" )
112 {
113 public void action( IAsn1Container container ) throws DecoderException
114 {
115 PagedSearchControlContainer pagedSearchContainer = ( PagedSearchControlContainer ) container;
116 Value value = pagedSearchContainer.getCurrentTLV().getValue();
117
118 try
119 {
120 // Check that the value is into the allowed interval
121 int size = IntegerDecoder.parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE );
122
123 // We allow negative value to absorb a bug in some M$ client.
124 // Those negative values will be transformed to Integer.MAX_VALUE.
125 if ( size < 0 )
126 {
127 size = Integer.MAX_VALUE;
128 }
129
130 if ( IS_DEBUG )
131 {
132 log.debug( "size = " + size );
133 }
134
135 pagedSearchContainer.getPagedSearchControl().setSize( size );
136 }
137 catch ( IntegerDecoderException e )
138 {
139 String msg = "failed to decode the size for PagedSearchControl";
140 log.error( msg, e );
141 throw new DecoderException( msg );
142 }
143 }
144 } );
145
146 /**
147 * Transition from size to cookie
148 * realSearchControlValue ::= SEQUENCE OF {
149 * ...
150 * cookie OCTET STRING
151 * }
152 *
153 * Stores the cookie flag
154 */
155 super.transitions[PagedSearchControlStatesEnum.SIZE_STATE][UniversalTag.OCTET_STRING_TAG] =
156 new GrammarTransition( PagedSearchControlStatesEnum.SIZE_STATE,
157 PagedSearchControlStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING_TAG,
158 new GrammarAction( "Set PagedSearchControl cookie" )
159 {
160 public void action( IAsn1Container container ) throws DecoderException
161 {
162 PagedSearchControlContainer pagedSearchContainer = ( PagedSearchControlContainer ) container;
163 Value value = pagedSearchContainer.getCurrentTLV().getValue();
164
165 if ( pagedSearchContainer.getCurrentTLV().getLength() == 0 )
166 {
167 pagedSearchContainer.getPagedSearchControl().setCookie( StringTools.EMPTY_BYTES );
168 }
169 else
170 {
171 pagedSearchContainer.getPagedSearchControl().setCookie( value.getData() );
172 }
173
174 // We can have an END transition
175 pagedSearchContainer.grammarEndAllowed( true );
176 }
177 } );
178 }
179
180
181 /**
182 * This class is a singleton.
183 *
184 * @return An instance on this grammar
185 */
186 public static IGrammar getInstance()
187 {
188 return instance;
189 }
190 }