View Javadoc

1   /*
2    *   Copyright 2005 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.asn1new.ber.grammar;
18  
19  import org.apache.asn1new.Asn1Object;
20  import org.apache.asn1.codec.DecoderException;
21  import org.apache.asn1new.ber.containers.IAsn1Container;
22  import org.apache.asn1new.ber.tlv.TLV;
23  import org.apache.asn1new.ber.tlv.Tag;
24  import org.apache.asn1new.util.StringUtils;
25  import org.slf4j.LoggerFactory;
26  
27  import org.slf4j.Logger;
28  
29  
30  /***
31   * The abstract IGrammar which is the Mother of all the grammars. It
32   * contains the transitions table.
33   * 
34   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
35   */
36  public abstract class AbstractGrammar implements IGrammar
37  {
38      //~ Static fields/initializers -----------------------------------------------------------------
39  
40      /*** The logger */
41      private static final Logger log = LoggerFactory.getLogger( AbstractGrammar.class );
42  
43      /*** A speedup for logs */
44      private static boolean DEBUG;
45  
46      //~ Instance fields ----------------------------------------------------------------------------
47  
48      /*** Table of transitions. It's a two dimension array, the first dimension
49       * indice the states, the second dimension indices the Tag value, so it is 256 wide. */
50      protected GrammarTransition[][] transitions;
51  
52      /*** The grammar name */
53      protected String name;
54  
55      /*** The grammar's states */
56      protected IStates statesEnum;
57      
58      public AbstractGrammar()
59      {
60      	DEBUG = log.isDebugEnabled();
61      }
62  
63      //~ Methods ------------------------------------------------------------------------------------
64  
65      /***
66       * Return the grammar's name
67       * @return The grammar name
68      */
69      public String getName()
70      {
71          return name;
72      }
73  
74      /***
75       * Set the grammar's name
76       * @param name DOCUMENT ME!
77      */
78      public void setName( String name )
79      {
80          this.name = name;
81      }
82  
83      /***
84       * Checks the Length. If the current TLV length is above the expected length of the 
85       * PDU, an exception is thrown.
86       * 
87       * The current Object contains the sum of all included Objects and element, which is
88       * compared with the PDU's expected length (the Length part of the PDU containing the Object).
89       * 
90       * @param object The Object that is being decoded.
91       * @param tlv The current TLV
92       * @throws DecoderException Thrown if the expected length is lower than the sum
93       * of all the included elements.
94       */
95      protected void checkLength( Asn1Object object, TLV tlv ) throws DecoderException
96      {
97  
98          // Create a new expected Length
99          int expectedLength = tlv.getLength().getLength();
100 
101         int tlvLength      = tlv.getSize();
102 
103         if ( DEBUG )
104         {
105             log.debug(
106                 "Expected Length = " + ( ( Asn1Object ) object ).getExpectedLength() +
107                 ", current length = " + ( ( Asn1Object ) object ).getCurrentLength() +
108                 ", added length = " + expectedLength +
109                 ", tlv length = " + tlvLength );
110         }
111 
112         // We already are at the top level.
113         // An exception will be thrown if the current length exceed the expected length
114         ( ( Asn1Object ) object ).addLength( tlvLength );
115     }
116 
117     /***
118      * Get the transition associated with the state and tag
119      * @param state The current state
120      * @param tag The current tag
121      * @return A valid transition if any, or null.
122      */
123     public GrammarTransition getTransition( int state, int tag )
124     {
125         return transitions[state][tag & IStates.STATES_SWITCH_MASK];
126     }
127 
128     /***
129      * The main function. This is where an action is executed. If the 
130      * action is null, nothing is done.
131      *
132      * @param container The Asn1Container 
133      *
134      * @throws DecoderException Thrown if anything went wrong
135      */
136     public void executeAction( IAsn1Container container ) throws DecoderException
137     {
138 
139         int      currentState   = container.getTransition();
140         IGrammar currentGrammar = container.getGrammar();
141 
142         // We have to deal with the special case of a GRAMMAR_END state
143         if ( currentState == IStates.END_STATE )
144         {
145             currentState = container.restoreGrammar();
146 
147             if ( currentState == IStates.END_STATE )
148             {
149                 return;
150             }
151         }
152 
153         Tag  tag     = container.getCurrentTLV().getTag();
154         byte tagByte = tag.getTagByte();
155 
156         // We will loop until no more actions are to be executed
157         while ( true )
158         {
159 
160             GrammarTransition transition = ( ( AbstractGrammar ) container.getGrammar() )
161                 .getTransition( currentState, tagByte & IStates.STATES_SWITCH_MASK );
162 
163             if ( transition == null )
164             {
165 
166                 if ( container.getCurrentGrammar() == 0 )
167                 {
168                 	String errorMessage = "Bad transition from state " +
169                         currentGrammar.getStatesEnum().getState( container.getCurrentGrammarType(),
170                             currentState ) + ", tag " + StringUtils.dumpByte( tag.getTagByte() );
171                 	
172                 	log.error( errorMessage );
173                 	
174                     // If we have no more grammar on the stack, then this is an error
175                     throw new DecoderException( "Bad transition !" );
176                 }
177                 else
178                 {
179 
180                     // We have finished with the current grammar, so we have to continue with the
181                     // previous one.
182                     currentState = container.restoreGrammar();
183                     continue;
184                 }
185             }
186 
187             if ( DEBUG )
188             {
189                 log.debug( transition.toString( container.getCurrentGrammarType(),
190                         currentGrammar.getStatesEnum() ) );
191             }
192 
193             int nextState = transition.getNextState();
194 
195             if ( ( ( nextState & IStates.GRAMMAR_SWITCH_MASK ) != 0 ) &&
196                     ( nextState != IStates.END_STATE ) )
197             {
198 
199                 if ( DEBUG )
200                 {
201                     log.debug(
202                         "Switching from grammar " +
203                         container.getStates().getGrammarName( currentGrammar ) +
204                         " to grammar " + container.getStates().getGrammarName( ( nextState >> 8 ) - 1 ) );
205                 }
206 
207                 // We have a grammar switch, so we change the current state to the initial
208                 // state in the new grammar and loop.
209                 container.switchGrammar( currentState, nextState & IStates.GRAMMAR_SWITCH_MASK );
210                 currentState = IStates.INIT_GRAMMAR_STATE;
211             }
212             else
213             {
214 
215                 // This is not a grammar switch, so we execute the
216                 // action if we have one, and we quit the loop.
217                 container.setTransition( nextState );
218 
219                 if ( transition.hasAction() )
220                 {
221                     transition.getAction().action( container );
222                 }
223 
224                 break;
225             }
226         }
227     }
228 
229     /***
230      * Get the states of the current grammar
231      *
232      * @return Returns the statesEnum.
233      */
234     public IStates getStatesEnum()
235     {
236         return statesEnum;
237     }
238 
239     /***
240      * Set the states for this grammar
241      *
242      * @param statesEnum The statesEnum to set.
243      */
244     public void setStatesEnum( IStates statesEnum )
245     {
246         this.statesEnum = statesEnum;
247     }
248 }