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   *    https://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.entryChange;
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.LongDecoder;
32  import org.apache.directory.api.asn1.ber.tlv.LongDecoderException;
33  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
34  import org.apache.directory.api.i18n.I18n;
35  import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
36  import org.apache.directory.api.ldap.model.message.controls.ChangeType;
37  import org.apache.directory.api.ldap.model.name.Dn;
38  import org.apache.directory.api.util.Strings;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  
43  /**
44   * This class implements the EntryChangeControl. All the actions are declared in
45   * this class. As it is a singleton, these declaration are only done once.
46   * 
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   */
49  public final class EntryChangeGrammar extends AbstractGrammar<EntryChangeContainer>
50  {
51      /** The logger */
52      static final Logger LOG = LoggerFactory.getLogger( EntryChangeGrammar.class );
53  
54      /** The instance of grammar. EntryChangeGrammar is a singleton */
55      private static Grammar<?> instance = new EntryChangeGrammar();
56  
57  
58      /**
59       * Creates a new EntryChangeGrammar object.
60       */
61      @SuppressWarnings("unchecked")
62      private EntryChangeGrammar()
63      {
64          setName( EntryChangeGrammar.class.getName() );
65  
66          // Create the transitions table
67          super.transitions = new GrammarTransition[EntryChangeStates.LAST_EC_STATE.ordinal()][256];
68  
69          // ============================================================================================
70          // Transition from start state to Entry Change sequence
71          // ============================================================================================
72          // EntryChangeNotification ::= SEQUENCE {
73          //     ...
74          //
75          // Initialization of the structure
76          super.transitions[EntryChangeStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
77              new GrammarTransition<EntryChangeContainer>( EntryChangeStates.START_STATE,
78                  EntryChangeStates.EC_SEQUENCE_STATE,
79                  UniversalTag.SEQUENCE.getValue(), null );
80  
81          // ============================================================================================
82          // transition from Entry Change sequence to Change Type
83          // ============================================================================================
84          // EntryChangeNotification ::= SEQUENCE {
85          //     changeType ENUMERATED {
86          //     ...
87          //
88          // Evaluates the changeType
89          super.transitions[EntryChangeStates.EC_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] =
90              new GrammarTransition<EntryChangeContainer>( EntryChangeStates.EC_SEQUENCE_STATE,
91                  EntryChangeStates.CHANGE_TYPE_STATE,
92                  UniversalTag.ENUMERATED.getValue(),
93                  new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl changeType" )
94                  {
95                      public void action( EntryChangeContainer container ) throws DecoderException
96                      {
97                          BerValue value = container.getCurrentTLV().getValue();
98  
99                          try
100                         {
101                             int change = IntegerDecoder.parse( value, 1, 8 );
102 
103                             switch ( ChangeType.getChangeType( change ) )
104                             {
105                                 case ADD:
106                                 case DELETE:
107                                 case MODDN:
108                                 case MODIFY:
109                                     ChangeType changeType = ChangeType.getChangeType( change );
110 
111                                     if ( LOG.isDebugEnabled() )
112                                     {
113                                         LOG.debug( I18n.msg( I18n.MSG_05300_CHANGE_TYPE, changeType ) );
114                                     }
115 
116                                     container.getEntryChange().setChangeType( changeType );
117                                     break;
118 
119                                 default:
120                                     String msg = I18n.err( I18n.ERR_05300_CANT_DECODE_CHANGE_TYPE );
121                                     LOG.error( msg );
122                                     throw new DecoderException( msg );
123                             }
124 
125                             // We can have an END transition
126                             container.setGrammarEndAllowed( true );
127                         }
128                         catch ( IntegerDecoderException ide )
129                         {
130                             String msg = I18n.err( I18n.ERR_05300_CANT_DECODE_CHANGE_TYPE );
131                             LOG.error( msg, ide );
132                             throw new DecoderException( msg, ide );
133                         }
134                         catch ( IllegalArgumentException iae )
135                         {
136                             throw new DecoderException( iae.getLocalizedMessage(), iae );
137                         }
138                     }
139                 } );
140 
141         // ============================================================================================
142         // Transition from Change Type to Previous Dn
143         // ============================================================================================
144         // EntryChangeNotification ::= SEQUENCE {
145         //     ...
146         //     previousDN LDAPDN OPTIONAL,
147         //     ...
148         //
149         // Set the previousDN into the structure. We first check that it's a
150         // valid Dn
151         super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
152             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
153                 EntryChangeStates.PREVIOUS_DN_STATE,
154                 UniversalTag.OCTET_STRING.getValue(),
155                 new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl previousDN" )
156                 {
157                     public void action( EntryChangeContainer container ) throws DecoderException
158                     {
159                         ChangeType changeType = container.getEntryChange().getChangeType();
160 
161                         if ( changeType != ChangeType.MODDN )
162                         {
163                             LOG.error( I18n.err( I18n.ERR_05301_INVALID_PREVIOUS_DN ) );
164                             throw new DecoderException( I18n.err( I18n.ERR_05302_PREVIOUS_DN_NOT_ALLOWED ) );
165                         }
166                         else
167                         {
168                             BerValue value = container.getCurrentTLV().getValue();
169                             Dn previousDn;
170 
171                             try
172                             {
173                                 previousDn = new Dn( Strings.utf8ToString( value.getData() ) );
174                             }
175                             catch ( LdapInvalidDnException ine )
176                             {
177                                 LOG.error( I18n.err( I18n.ERR_05303_BAD_PREVIOUS_DN, Strings.dumpBytes( value.getData() ) ) );
178                                 throw new DecoderException( I18n.err( I18n.ERR_05304_FAILED_TO_DECODE_PREVIOUS_DN ), ine );
179                             }
180 
181                             if ( LOG.isDebugEnabled() )
182                             {
183                                 LOG.debug( I18n.msg( I18n.MSG_05301_PREVIOUS_DN, previousDn ) );
184                             }
185 
186                             container.getEntryChange().setPreviousDn( previousDn );
187 
188                             // We can have an END transition
189                             container.setGrammarEndAllowed( true );
190                         }
191                     }
192                 } );
193 
194         // Change Number action
195         GrammarAction<EntryChangeContainer> setChangeNumberAction = new GrammarAction<EntryChangeContainer>(
196             "Set EntryChangeControl changeNumber" )
197         {
198             public void action( EntryChangeContainer container ) throws DecoderException
199             {
200                 BerValue value = container.getCurrentTLV().getValue();
201 
202                 try
203                 {
204                     long changeNumber = LongDecoder.parse( value );
205 
206                     if ( LOG.isDebugEnabled() )
207                     {
208                         LOG.debug( I18n.msg( I18n.MSG_05302_CHANGE_NUMBER, changeNumber ) );
209                     }
210 
211                     container.getEntryChange().setChangeNumber( changeNumber );
212 
213                     // We can have an END transition
214                     container.setGrammarEndAllowed( true );
215                 }
216                 catch ( LongDecoderException lde )
217                 {
218                     String msg = I18n.err( I18n.ERR_05305_CHANGE_NUMBER_DECODING_ERROR );
219                     LOG.error( msg, lde );
220                     throw new DecoderException( msg, lde );
221                 }
222             }
223         };
224 
225         // ============================================================================================
226         // Transition from Previous Dn to Change Number
227         // ============================================================================================
228         // EntryChangeNotification ::= SEQUENCE {
229         //     ...
230         //     changeNumber INTEGER OPTIONAL
231         // }
232         //
233         // Set the changeNumber into the structure
234         super.transitions[EntryChangeStates.PREVIOUS_DN_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
235             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.PREVIOUS_DN_STATE,
236                 EntryChangeStates.CHANGE_NUMBER_STATE,
237                 UniversalTag.INTEGER.getValue(),
238                 setChangeNumberAction );
239 
240         // ============================================================================================
241         // Transition from Previous Dn to Change Number
242         // ============================================================================================
243         // EntryChangeNotification ::= SEQUENCE {
244         //     ...
245         //     changeNumber INTEGER OPTIONAL
246         // }
247         //
248         // Set the changeNumber into the structure
249         super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
250             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
251                 EntryChangeStates.CHANGE_NUMBER_STATE,
252                 UniversalTag.INTEGER.getValue(),
253                 setChangeNumberAction );
254     }
255 
256 
257     /**
258      * This class is a singleton.
259      * 
260      * @return An instance on this grammar
261      */
262     public static Grammar<?> getInstance()
263     {
264         return instance;
265     }
266 }