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.entryChange;
021
022
023 import javax.naming.InvalidNameException;
024
025 import org.apache.directory.shared.asn1.ber.IAsn1Container;
026 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
027 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
028 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
029 import org.apache.directory.shared.asn1.ber.grammar.IGrammar;
030 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031 import org.apache.directory.shared.asn1.ber.tlv.Value;
032 import org.apache.directory.shared.asn1.codec.DecoderException;
033 import org.apache.directory.shared.asn1.util.IntegerDecoder;
034 import org.apache.directory.shared.asn1.util.IntegerDecoderException;
035 import org.apache.directory.shared.asn1.util.LongDecoder;
036 import org.apache.directory.shared.asn1.util.LongDecoderException;
037 import org.apache.directory.shared.ldap.codec.search.controls.ChangeType;
038 import org.apache.directory.shared.ldap.name.LdapDN;
039 import org.apache.directory.shared.ldap.util.StringTools;
040 import org.slf4j.Logger;
041 import org.slf4j.LoggerFactory;
042
043
044 /**
045 * This class implements the EntryChangeControl. All the actions are declared in
046 * this class. As it is a singleton, these declaration are only done once.
047 *
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 * @version $Rev: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 2009) $,
050 */
051 public class EntryChangeControlGrammar extends AbstractGrammar
052 {
053 /** The logger */
054 static final Logger log = LoggerFactory.getLogger( EntryChangeControlGrammar.class );
055
056 /** Speedup for logs */
057 static final boolean IS_DEBUG = log.isDebugEnabled();
058
059 /** The instance of grammar. EntryChangeControlGrammar is a singleton */
060 private static IGrammar instance = new EntryChangeControlGrammar();
061
062
063 /**
064 * Creates a new EntryChangeControlGrammar object.
065 */
066 private EntryChangeControlGrammar()
067 {
068 name = EntryChangeControlGrammar.class.getName();
069 statesEnum = EntryChangeControlStatesEnum.getInstance();
070
071 // Create the transitions table
072 super.transitions = new GrammarTransition[EntryChangeControlStatesEnum.LAST_EC_STATE][256];
073
074 // ============================================================================================
075 // Transition from start state to Entry Change sequence
076 // ============================================================================================
077 // EntryChangeNotification ::= SEQUENCE {
078 // ...
079 //
080 // Initialization of the structure
081 super.transitions[EntryChangeControlStatesEnum.START_STATE][UniversalTag.SEQUENCE_TAG] =
082 new GrammarTransition( EntryChangeControlStatesEnum.START_STATE,
083 EntryChangeControlStatesEnum.EC_SEQUENCE_STATE,
084 UniversalTag.SEQUENCE_TAG,
085 new GrammarAction( "Init EntryChangeControl" )
086 {
087 public void action( IAsn1Container container )
088 {
089 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
090 EntryChangeControlCodec control = new EntryChangeControlCodec();
091 entryChangeContainer.setEntryChangeControl( control );
092 }
093 } );
094
095 // ============================================================================================
096 // transition from Entry Change sequence to Change Type
097 // ============================================================================================
098 // EntryChangeNotification ::= SEQUENCE {
099 // changeType ENUMERATED {
100 // ...
101 //
102 // Evaluates the changeType
103 super.transitions[EntryChangeControlStatesEnum.EC_SEQUENCE_STATE][UniversalTag.ENUMERATED_TAG] =
104 new GrammarTransition( EntryChangeControlStatesEnum.EC_SEQUENCE_STATE,
105 EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
106 UniversalTag.ENUMERATED_TAG,
107 new GrammarAction( "Set EntryChangeControl changeType" )
108 {
109 public void action( IAsn1Container container ) throws DecoderException
110 {
111 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
112 Value value = entryChangeContainer.getCurrentTLV().getValue();
113
114 try
115 {
116 int change = IntegerDecoder.parse( value, 1, 8 );
117
118 switch ( change )
119 {
120 case ChangeType.ADD_VALUE:
121 case ChangeType.DELETE_VALUE:
122 case ChangeType.MODDN_VALUE:
123 case ChangeType.MODIFY_VALUE:
124 ChangeType changeType = ChangeType.getChangeType( change );
125
126 if ( IS_DEBUG )
127 {
128 log.debug( "changeType = " + changeType );
129 }
130
131 entryChangeContainer.getEntryChangeControl().setChangeType( changeType );
132 break;
133
134 default:
135 String msg = "failed to decode the changeType for EntryChangeControl";
136 log.error( msg );
137 throw new DecoderException( msg );
138 }
139
140 // We can have an END transition
141 entryChangeContainer.grammarEndAllowed( true );
142 }
143 catch ( IntegerDecoderException e )
144 {
145 String msg = "failed to decode the changeType for EntryChangeControl";
146 log.error( msg, e );
147 throw new DecoderException( msg );
148 }
149 }
150 } );
151
152 // ============================================================================================
153 // Transition from Change Type to Previous DN
154 // ============================================================================================
155 // EntryChangeNotification ::= SEQUENCE {
156 // ...
157 // previousDN LDAPDN OPTIONAL,
158 // ...
159 //
160 // Set the previousDN into the structure. We first check that it's a
161 // valid DN
162 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.OCTET_STRING_TAG] =
163 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
164 EntryChangeControlStatesEnum.PREVIOUS_DN_STATE,
165 UniversalTag.OCTET_STRING_TAG,
166 new GrammarAction( "Set EntryChangeControl previousDN" )
167 {
168 public void action( IAsn1Container container ) throws DecoderException
169 {
170 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
171
172 ChangeType changeType = entryChangeContainer.getEntryChangeControl().getChangeType();
173
174 if ( changeType != ChangeType.MODDN )
175 {
176 log.error( "The previousDN field should not contain anything if the changeType is not MODDN" );
177 throw new DecoderException( "Previous DN is not allowed for this change type" );
178 }
179 else
180 {
181 Value value = entryChangeContainer.getCurrentTLV().getValue();
182 LdapDN previousDn = null;
183
184 try
185 {
186 previousDn = new LdapDN( StringTools.utf8ToString( value.getData() ) );
187 }
188 catch ( InvalidNameException ine )
189 {
190 log.error( "Bad Previous DN : '" + StringTools.dumpBytes( value.getData() ) );
191 throw new DecoderException( "failed to decode the previous DN" );
192 }
193
194 if ( IS_DEBUG )
195 {
196 log.debug( "previousDN = " + previousDn );
197 }
198
199 entryChangeContainer.getEntryChangeControl().setPreviousDn( previousDn );
200
201 // We can have an END transition
202 entryChangeContainer.grammarEndAllowed( true );
203 }
204 }
205 } );
206
207 // Change Number action
208 GrammarAction setChangeNumberAction = new GrammarAction( "Set EntryChangeControl changeNumber" )
209 {
210 public void action( IAsn1Container container ) throws DecoderException
211 {
212 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
213 Value value = entryChangeContainer.getCurrentTLV().getValue();
214
215 try
216 {
217 long changeNumber = LongDecoder.parse( value );
218
219 if ( IS_DEBUG )
220 {
221 log.debug( "changeNumber = " + changeNumber );
222 }
223
224 entryChangeContainer.getEntryChangeControl().setChangeNumber( changeNumber );
225
226 // We can have an END transition
227 entryChangeContainer.grammarEndAllowed( true );
228 }
229 catch ( LongDecoderException e )
230 {
231 String msg = "failed to decode the changeNumber for EntryChangeControl";
232 log.error( msg, e );
233 throw new DecoderException( msg );
234 }
235 }
236 };
237
238 // ============================================================================================
239 // Transition from Previous DN to Change Number
240 // ============================================================================================
241 // EntryChangeNotification ::= SEQUENCE {
242 // ...
243 // changeNumber INTEGER OPTIONAL
244 // }
245 //
246 // Set the changeNumber into the structure
247 super.transitions[EntryChangeControlStatesEnum.PREVIOUS_DN_STATE][UniversalTag.INTEGER_TAG] =
248 new GrammarTransition( EntryChangeControlStatesEnum.PREVIOUS_DN_STATE,
249 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE,
250 UniversalTag.INTEGER_TAG,
251 setChangeNumberAction );
252
253 // ============================================================================================
254 // Transition from Previous DN to Change Number
255 // ============================================================================================
256 // EntryChangeNotification ::= SEQUENCE {
257 // ...
258 // changeNumber INTEGER OPTIONAL
259 // }
260 //
261 // Set the changeNumber into the structure
262 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.INTEGER_TAG] =
263 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
264 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE,
265 UniversalTag.INTEGER_TAG,
266 setChangeNumberAction );
267 }
268
269
270 /**
271 * This class is a singleton.
272 *
273 * @return An instance on this grammar
274 */
275 public static IGrammar getInstance()
276 {
277 return instance;
278 }
279 }