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