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.dsmlv2;
21  
22  
23  import java.io.FileNotFoundException;
24  import java.io.FileReader;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.Reader;
28  import java.io.StringReader;
29  
30  import org.apache.directory.api.dsmlv2.reponse.BatchResponseDsml;
31  import org.apache.directory.api.dsmlv2.reponse.Dsmlv2ResponseGrammar;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.codec.api.LdapApiService;
34  import org.apache.directory.api.ldap.model.message.Response;
35  import org.apache.directory.api.util.Strings;
36  import org.xmlpull.v1.XmlPullParser;
37  import org.xmlpull.v1.XmlPullParserException;
38  import org.xmlpull.v1.XmlPullParserFactory;
39  
40  
41  /**
42   * This class represents the DSMLv2 Parser.
43   * It can be used to parse a DSMLv2 Response input.
44   *
45   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
46   */
47  public class Dsmlv2ResponseParser
48  {
49      /** The associated DSMLv2 container */
50      private Dsmlv2Container container;
51  
52  
53      /**
54       * Creates a new instance of Dsmlv2ResponseParser.
55       *
56       * @throws XmlPullParserException if an error occurs while the initialization of the parser
57       */
58      public Dsmlv2ResponseParser( LdapApiService codec ) throws XmlPullParserException
59      {
60          this.container = new Dsmlv2Container( codec );
61  
62          this.container.setGrammar( Dsmlv2ResponseGrammar.getInstance() );
63  
64          XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
65          factory.setNamespaceAware( true );
66          XmlPullParser xpp = factory.newPullParser();
67  
68          container.setParser( xpp );
69      }
70  
71  
72      /**
73       * Sets the input string the parser is going to parse
74       *
75       * @param str the string the parser is going to parse
76       * @throws XmlPullParserException if an error occurs in the parser
77       */
78      public void setInput( String str ) throws XmlPullParserException
79      {
80          container.getParser().setInput( new StringReader( str ) );
81      }
82  
83  
84      /**
85       * Sets the input file the parser is going to parse
86       *
87       * @param fileName the name of the file
88       * @throws FileNotFoundException if the file does not exist
89       * @throws XmlPullParserException if an error occurs in the parser
90       */
91      public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException
92      {
93          Reader reader = new FileReader( fileName );
94          container.getParser().setInput( reader );
95      }
96  
97  
98      /**
99       * Sets the input stream the parser is going to process
100      *
101      * @param inputStream contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null)
102      * @param inputEncoding if not null it MUST be used as encoding for inputStream
103      * @throws XmlPullParserException if an error occurs in the parser
104      */
105     public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
106     {
107         container.getParser().setInput( inputStream, inputEncoding );
108     }
109 
110 
111     /**
112      * Launches the parsing on the input
113      * 
114      * @throws XmlPullParserException when an unrecoverable error occurs
115      * @throws IOException when an IO exception occurs
116      */
117     public void parse() throws XmlPullParserException, IOException
118     {
119         Dsmlv2ResponseGrammar grammar = Dsmlv2ResponseGrammar.getInstance();
120 
121         grammar.executeAction( container );
122     }
123 
124 
125     /**
126      * Launches the parsing of the Batch Response only
127      *
128      * @throws XmlPullParserException if an error occurs in the parser
129      */
130     public void parseBatchResponse() throws XmlPullParserException
131     {
132         XmlPullParser xpp = container.getParser();
133 
134         int eventType = xpp.getEventType();
135         
136         do
137         {
138             switch ( eventType )
139             {
140                 case XmlPullParser.START_DOCUMENT :
141                     container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
142                     break;
143 
144                 case XmlPullParser.END_DOCUMENT :
145                     container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
146                     break;
147 
148                 case XmlPullParser.START_TAG :
149                     processTag( container, Tag.START );
150                     break;
151 
152                 case XmlPullParser.END_TAG :
153                     processTag( container, Tag.END );
154                     break;
155             }
156             
157             try
158             {
159                 eventType = xpp.next();
160             }
161             catch ( IOException e )
162             {
163                 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
164             }
165         }
166         while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
167     }
168 
169 
170     /**
171      * Processes the task required in the grammar to the given tag type
172      *
173      * @param container the DSML container
174      * @param tagType the tag type
175      * @throws XmlPullParserException when an error occurs during the parsing
176      */
177     private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
178     {
179         XmlPullParser xpp = container.getParser();
180 
181         String tagName = Strings.toLowerCase( xpp.getName() );
182 
183         GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) );
184 
185         if ( transition != null )
186         {
187             container.setState( transition.getNextState() );
188 
189             if ( transition.hasAction() )
190             {
191                 transition.getAction().action( container );
192             }
193         }
194         else
195         {
196             throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
197         }
198     }
199 
200 
201     /**
202      * Gets the Batch Response or null if the it has not been parsed yet
203      *
204      * @return the Batch Response or null if the it has not been parsed yet
205      */
206     public BatchResponseDsml getBatchResponse()
207     {
208         return container.getBatchResponse();
209     }
210 
211 
212     /**
213      * Returns the next Request or null if there's no more request
214      * @return the next Request or null if there's no more request
215      * @throws XmlPullParserException when an error occurs during the parsing
216      */
217     public DsmlDecorator<? extends Response> getNextResponse() throws XmlPullParserException
218     {
219         if ( container.getBatchResponse() == null )
220         {
221             parseBatchResponse();
222         }
223 
224         XmlPullParser xpp = container.getParser();
225 
226         int eventType = xpp.getEventType();
227         do
228         {
229             while ( eventType == XmlPullParser.TEXT )
230             {
231                 try
232                 {
233                     xpp.next();
234                 }
235                 catch ( IOException e )
236                 {
237                     throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
238                 }
239                 eventType = xpp.getEventType();
240             }
241 
242             switch ( eventType )
243             {
244                 case XmlPullParser.START_DOCUMENT :
245                     container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
246                     break;
247 
248                 case XmlPullParser.END_DOCUMENT :
249                     container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
250                     return null;
251 
252                 case XmlPullParser.START_TAG :
253                     processTag( container, Tag.START );
254                     break;
255 
256                 case XmlPullParser.END_TAG :
257                     processTag( container, Tag.END );
258                     break;
259             }
260             
261             try
262             {
263                 eventType = xpp.next();
264             }
265             catch ( IOException e )
266             {
267                 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
268             }
269         }
270         while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
271 
272         return container.getBatchResponse().getCurrentResponse();
273     }
274 
275 
276     /**
277      * Parses all the responses
278      *
279      * @throws XmlPullParserException when an error occurs during the parsing
280      */
281     public void parseAllResponses() throws XmlPullParserException
282     {
283         while ( getNextResponse() != null )
284         {
285             continue;
286         }
287     }
288 }