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   *    http://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      /** Speedup for logs */
55      static final boolean IS_DEBUG = LOG.isDebugEnabled();
56  
57      /** The instance of grammar. EntryChangeGrammar is a singleton */
58      private static Grammar<?> instance = new EntryChangeGrammar();
59  
60  
61      /**
62       * Creates a new EntryChangeGrammar object.
63       */
64      @SuppressWarnings("unchecked")
65      private EntryChangeGrammar()
66      {
67          setName( EntryChangeGrammar.class.getName() );
68  
69          // Create the transitions table
70          super.transitions = new GrammarTransition[EntryChangeStates.LAST_EC_STATE.ordinal()][256];
71  
72          // ============================================================================================
73          // Transition from start state to Entry Change sequence
74          // ============================================================================================
75          // EntryChangeNotification ::= SEQUENCE {
76          //     ...
77          //
78          // Initialization of the structure
79          super.transitions[EntryChangeStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
80              new GrammarTransition<EntryChangeContainer>( EntryChangeStates.START_STATE,
81                  EntryChangeStates.EC_SEQUENCE_STATE,
82                  UniversalTag.SEQUENCE.getValue(), null );
83  
84          // ============================================================================================
85          // transition from Entry Change sequence to Change Type
86          // ============================================================================================
87          // EntryChangeNotification ::= SEQUENCE {
88          //     changeType ENUMERATED {
89          //     ...
90          //
91          // Evaluates the changeType
92          super.transitions[EntryChangeStates.EC_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] =
93              new GrammarTransition<EntryChangeContainer>( EntryChangeStates.EC_SEQUENCE_STATE,
94                  EntryChangeStates.CHANGE_TYPE_STATE,
95                  UniversalTag.ENUMERATED.getValue(),
96                  new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl changeType" )
97                  {
98                      public void action( EntryChangeContainer container ) throws DecoderException
99                      {
100                         BerValue value = container.getCurrentTLV().getValue();
101 
102                         try
103                         {
104                             int change = IntegerDecoder.parse( value, 1, 8 );
105 
106                             switch ( ChangeType.getChangeType( change ) )
107                             {
108                                 case ADD:
109                                 case DELETE:
110                                 case MODDN:
111                                 case MODIFY:
112                                     ChangeType changeType = ChangeType.getChangeType( change );
113 
114                                     if ( IS_DEBUG )
115                                     {
116                                         LOG.debug( "changeType = " + changeType );
117                                     }
118 
119                                     container.getEntryChangeDecorator().setChangeType( changeType );
120                                     break;
121 
122                                 default:
123                                     String msg = I18n.err( I18n.ERR_04044 );
124                                     LOG.error( msg );
125                                     throw new DecoderException( msg );
126                             }
127 
128                             // We can have an END transition
129                             container.setGrammarEndAllowed( true );
130                         }
131                         catch ( IntegerDecoderException ide )
132                         {
133                             String msg = I18n.err( I18n.ERR_04044 );
134                             LOG.error( msg, ide );
135                             throw new DecoderException( msg, ide );
136                         }
137                         catch ( IllegalArgumentException iae )
138                         {
139                             throw new DecoderException( iae.getLocalizedMessage(), iae );
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[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
155             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
156                 EntryChangeStates.PREVIOUS_DN_STATE,
157                 UniversalTag.OCTET_STRING.getValue(),
158                 new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl previousDN" )
159                 {
160                     public void action( EntryChangeContainer container ) throws DecoderException
161                     {
162                         ChangeType changeType = container.getEntryChangeDecorator().getChangeType();
163 
164                         if ( changeType != ChangeType.MODDN )
165                         {
166                             LOG.error( I18n.err( I18n.ERR_04045 ) );
167                             throw new DecoderException( I18n.err( I18n.ERR_04046 ) );
168                         }
169                         else
170                         {
171                             BerValue value = container.getCurrentTLV().getValue();
172                             Dn previousDn;
173 
174                             try
175                             {
176                                 previousDn = new Dn( Strings.utf8ToString( value.getData() ) );
177                             }
178                             catch ( LdapInvalidDnException ine )
179                             {
180                                 LOG.error( I18n.err( I18n.ERR_04047, Strings.dumpBytes( value.getData() ) ) );
181                                 throw new DecoderException( I18n.err( I18n.ERR_04048 ), ine );
182                             }
183 
184                             if ( IS_DEBUG )
185                             {
186                                 LOG.debug( "previousDN = " + previousDn );
187                             }
188 
189                             container.getEntryChangeDecorator().setPreviousDn( previousDn );
190 
191                             // We can have an END transition
192                             container.setGrammarEndAllowed( true );
193                         }
194                     }
195                 } );
196 
197         // Change Number action
198         GrammarAction<EntryChangeContainer> setChangeNumberAction = new GrammarAction<EntryChangeContainer>(
199             "Set EntryChangeControl changeNumber" )
200         {
201             public void action( EntryChangeContainer container ) throws DecoderException
202             {
203                 BerValue value = container.getCurrentTLV().getValue();
204 
205                 try
206                 {
207                     long changeNumber = LongDecoder.parse( value );
208 
209                     if ( IS_DEBUG )
210                     {
211                         LOG.debug( "changeNumber = " + changeNumber );
212                     }
213 
214                     container.getEntryChangeDecorator().setChangeNumber( changeNumber );
215 
216                     // We can have an END transition
217                     container.setGrammarEndAllowed( true );
218                 }
219                 catch ( LongDecoderException lde )
220                 {
221                     String msg = I18n.err( I18n.ERR_04049 );
222                     LOG.error( msg, lde );
223                     throw new DecoderException( msg, lde );
224                 }
225             }
226         };
227 
228         // ============================================================================================
229         // Transition from Previous Dn to Change Number
230         // ============================================================================================
231         // EntryChangeNotification ::= SEQUENCE {
232         //     ...
233         //     changeNumber INTEGER OPTIONAL
234         // }
235         //
236         // Set the changeNumber into the structure
237         super.transitions[EntryChangeStates.PREVIOUS_DN_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
238             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.PREVIOUS_DN_STATE,
239                 EntryChangeStates.CHANGE_NUMBER_STATE,
240                 UniversalTag.INTEGER.getValue(),
241                 setChangeNumberAction );
242 
243         // ============================================================================================
244         // Transition from Previous Dn to Change Number
245         // ============================================================================================
246         // EntryChangeNotification ::= SEQUENCE {
247         //     ...
248         //     changeNumber INTEGER OPTIONAL
249         // }
250         //
251         // Set the changeNumber into the structure
252         super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
253             new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
254                 EntryChangeStates.CHANGE_NUMBER_STATE,
255                 UniversalTag.INTEGER.getValue(),
256                 setChangeNumberAction );
257     }
258 
259 
260     /**
261      * This class is a singleton.
262      * 
263      * @return An instance on this grammar
264      */
265     public static Grammar<?> getInstance()
266     {
267         return instance;
268     }
269 }