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 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.tlv.UniversalTag;
029 import org.apache.directory.shared.asn1.ber.tlv.Value;
030 import org.apache.directory.shared.asn1.codec.DecoderException;
031 import org.apache.directory.shared.asn1.util.IntegerDecoder;
032 import org.apache.directory.shared.asn1.util.IntegerDecoderException;
033 import org.apache.directory.shared.asn1.util.LongDecoder;
034 import org.apache.directory.shared.asn1.util.LongDecoderException;
035 import org.apache.directory.shared.i18n.I18n;
036 import org.apache.directory.shared.ldap.codec.search.controls.ChangeType;
037 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
038 import org.apache.directory.shared.ldap.name.DN;
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: 923473 $, $Date: 2010-03-16 00:25:03 +0200 (Tue, 16 Mar 2010) $,
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, null );
085
086 // ============================================================================================
087 // transition from Entry Change sequence to Change Type
088 // ============================================================================================
089 // EntryChangeNotification ::= SEQUENCE {
090 // changeType ENUMERATED {
091 // ...
092 //
093 // Evaluates the changeType
094 super.transitions[EntryChangeControlStatesEnum.EC_SEQUENCE_STATE][UniversalTag.ENUMERATED_TAG] =
095 new GrammarTransition( EntryChangeControlStatesEnum.EC_SEQUENCE_STATE,
096 EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
097 UniversalTag.ENUMERATED_TAG,
098 new GrammarAction( "Set EntryChangeControl changeType" )
099 {
100 public void action( IAsn1Container container ) throws DecoderException
101 {
102 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
103 Value value = entryChangeContainer.getCurrentTLV().getValue();
104
105 try
106 {
107 int change = IntegerDecoder.parse( value, 1, 8 );
108
109 switch ( change )
110 {
111 case ChangeType.ADD_VALUE:
112 case ChangeType.DELETE_VALUE:
113 case ChangeType.MODDN_VALUE:
114 case ChangeType.MODIFY_VALUE:
115 ChangeType changeType = ChangeType.getChangeType( change );
116
117 if ( IS_DEBUG )
118 {
119 log.debug( "changeType = " + changeType );
120 }
121
122 entryChangeContainer.getEntryChangeControl().setChangeType( changeType );
123 break;
124
125 default:
126 String msg = I18n.err( I18n.ERR_04044 );
127 log.error( msg );
128 throw new DecoderException( msg );
129 }
130
131 // We can have an END transition
132 entryChangeContainer.grammarEndAllowed( true );
133 }
134 catch ( IntegerDecoderException e )
135 {
136 String msg = I18n.err( I18n.ERR_04044 );
137 log.error( msg, e );
138 throw new DecoderException( msg );
139 }
140 }
141 } );
142
143 // ============================================================================================
144 // Transition from Change Type to Previous DN
145 // ============================================================================================
146 // EntryChangeNotification ::= SEQUENCE {
147 // ...
148 // previousDN LDAPDN OPTIONAL,
149 // ...
150 //
151 // Set the previousDN into the structure. We first check that it's a
152 // valid DN
153 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.OCTET_STRING_TAG] =
154 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
155 EntryChangeControlStatesEnum.PREVIOUS_DN_STATE,
156 UniversalTag.OCTET_STRING_TAG,
157 new GrammarAction( "Set EntryChangeControl previousDN" )
158 {
159 public void action( IAsn1Container container ) throws DecoderException
160 {
161 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
162
163 ChangeType changeType = entryChangeContainer.getEntryChangeControl().getChangeType();
164
165 if ( changeType != ChangeType.MODDN )
166 {
167 log.error( I18n.err( I18n.ERR_04045 ) );
168 throw new DecoderException( I18n.err( I18n.ERR_04046 ));
169 }
170 else
171 {
172 Value value = entryChangeContainer.getCurrentTLV().getValue();
173 DN previousDn = null;
174
175 try
176 {
177 previousDn = new DN( StringTools.utf8ToString( value.getData() ) );
178 }
179 catch ( LdapInvalidDnException ine )
180 {
181 log.error( I18n.err( I18n.ERR_04047, StringTools.dumpBytes( value.getData() ) ) );
182 throw new DecoderException( I18n.err( I18n.ERR_04048 ) );
183 }
184
185 if ( IS_DEBUG )
186 {
187 log.debug( "previousDN = " + previousDn );
188 }
189
190 entryChangeContainer.getEntryChangeControl().setPreviousDn( previousDn );
191
192 // We can have an END transition
193 entryChangeContainer.grammarEndAllowed( true );
194 }
195 }
196 } );
197
198 // Change Number action
199 GrammarAction setChangeNumberAction = new GrammarAction( "Set EntryChangeControl changeNumber" )
200 {
201 public void action( IAsn1Container container ) throws DecoderException
202 {
203 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container;
204 Value value = entryChangeContainer.getCurrentTLV().getValue();
205
206 try
207 {
208 long changeNumber = LongDecoder.parse( value );
209
210 if ( IS_DEBUG )
211 {
212 log.debug( "changeNumber = " + changeNumber );
213 }
214
215 entryChangeContainer.getEntryChangeControl().setChangeNumber( changeNumber );
216
217 // We can have an END transition
218 entryChangeContainer.grammarEndAllowed( true );
219 }
220 catch ( LongDecoderException e )
221 {
222 String msg = I18n.err( I18n.ERR_04049 );
223 log.error( msg, e );
224 throw new DecoderException( msg );
225 }
226 }
227 };
228
229 // ============================================================================================
230 // Transition from Previous DN to Change Number
231 // ============================================================================================
232 // EntryChangeNotification ::= SEQUENCE {
233 // ...
234 // changeNumber INTEGER OPTIONAL
235 // }
236 //
237 // Set the changeNumber into the structure
238 super.transitions[EntryChangeControlStatesEnum.PREVIOUS_DN_STATE][UniversalTag.INTEGER_TAG] =
239 new GrammarTransition( EntryChangeControlStatesEnum.PREVIOUS_DN_STATE,
240 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE,
241 UniversalTag.INTEGER_TAG,
242 setChangeNumberAction );
243
244 // ============================================================================================
245 // Transition from Previous DN to Change Number
246 // ============================================================================================
247 // EntryChangeNotification ::= SEQUENCE {
248 // ...
249 // changeNumber INTEGER OPTIONAL
250 // }
251 //
252 // Set the changeNumber into the structure
253 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.INTEGER_TAG] =
254 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE,
255 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE,
256 UniversalTag.INTEGER_TAG,
257 setChangeNumberAction );
258 }
259
260
261 /**
262 * This class is a singleton.
263 *
264 * @return An instance on this grammar
265 */
266 public static IGrammar getInstance()
267 {
268 return instance;
269 }
270 }