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.request.BatchRequestDsml;
31  import org.apache.directory.api.dsmlv2.request.Dsmlv2Grammar;
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.model.message.Request;
34  import org.apache.directory.api.util.Strings;
35  import org.xmlpull.v1.XmlPullParser;
36  import org.xmlpull.v1.XmlPullParserException;
37  import org.xmlpull.v1.XmlPullParserFactory;
38  
39  
40  /**
41   * This class represents the DSMLv2 Parser.
42   * It can be used to parse a plain DSMLv2 Request input document or the one inside a SOAP envelop.
43   *
44   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
45   */
46  public class Dsmlv2Parser
47  {
48      /** The associated DSMLv2 container */
49      private Dsmlv2Container container;
50  
51      /**
52       * flag to indicate if the batch request should maintain a list of all the
53       * operation request objects present in the DSML document. Default is true
54       */
55      private boolean storeMsgInBatchReq = true;
56  
57      /** The thread safe DSMLv2 Grammar */
58      private Dsmlv2Grammar grammar;
59  
60  
61      /**
62       * Creates a new instance of Dsmlv2Parser.
63       *
64       * @throws XmlPullParserException if an error occurs during the initialization of the parser
65       */
66      public Dsmlv2Parser() throws XmlPullParserException
67      {
68          this( true );
69      }
70  
71  
72      /**
73       * Creates a new instance of Dsmlv2Parser.
74       *
75       * @param storeMsgInBatchReq flag to set if the parsed requests should b stored
76       * @throws XmlPullParserException if an error occurs during the initialization of the parser
77       */
78      public Dsmlv2Parser( boolean storeMsgInBatchReq ) throws XmlPullParserException
79      {
80          this.storeMsgInBatchReq = storeMsgInBatchReq;
81  
82          this.grammar = new Dsmlv2Grammar();
83          this.container = new Dsmlv2Container( grammar.getLdapCodecService() );
84  
85          this.container.setGrammar( grammar );
86  
87          XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
88          factory.setNamespaceAware( true );
89          XmlPullParser xpp = factory.newPullParser();
90  
91          container.setParser( xpp );
92      }
93  
94  
95      /**
96       * Creates a new instance of Dsmlv2Parser.
97       *
98       * @throws XmlPullParserException if an error occurs during the initialization of the parser
99       */
100     public Dsmlv2Parser( Dsmlv2Grammar grammar ) throws XmlPullParserException
101     {
102         this.container = new Dsmlv2Container( grammar.getLdapCodecService() );
103         this.container.setGrammar( grammar );
104         this.grammar = grammar;
105 
106         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
107         factory.setNamespaceAware( true );
108         XmlPullParser xpp = factory.newPullParser();
109 
110         container.setParser( xpp );
111     }
112 
113 
114     /**
115      * Sets the input file the parser is going to parse
116      *
117      * @param fileName the name of the file
118      * @throws FileNotFoundException if the file does not exist
119      * @throws XmlPullParserException if an error occurs in the parser
120      */
121     public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException
122     {
123         Reader reader = new FileReader( fileName );
124         container.getParser().setInput( reader );
125     }
126 
127 
128     /**
129      * Sets the input stream the parser is going to process
130      *
131      * @param inputStream contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null)
132      * @param inputEncoding if not null it MUST be used as encoding for inputStream
133      * @throws XmlPullParserException if an error occurs in the parser
134      */
135     public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
136     {
137         container.getParser().setInput( inputStream, inputEncoding );
138     }
139 
140 
141     /**
142      * Sets the input string the parser is going to parse
143      *
144      * @param str the string the parser is going to parse
145      * @throws XmlPullParserException if an error occurs in the parser
146      */
147     public void setInput( String str ) throws XmlPullParserException
148     {
149         container.getParser().setInput( new StringReader( str ) );
150     }
151 
152 
153     /**
154      * Launches the parsing on the input
155      * This method will parse the whole DSML document, without considering the flag {@link #storeMsgInBatchReq}
156      * @throws XmlPullParserException when an unrecoverable error occurs
157      * @throws IOException when an IO execption occurs
158      */
159     public void parse() throws XmlPullParserException, IOException
160     {
161         grammar.executeAction( container );
162     }
163 
164 
165     /**
166      * Launches the parsing of the Batch Request only
167      *
168      * @throws XmlPullParserException if an error occurs in the parser
169      */
170     public void parseBatchRequest() throws XmlPullParserException
171     {
172         XmlPullParser xpp = container.getParser();
173 
174         int eventType = xpp.getEventType();
175 
176         do
177         {
178             switch ( eventType )
179             {
180                 case XmlPullParser.START_DOCUMENT:
181                     container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
182                     break;
183 
184                 case XmlPullParser.END_DOCUMENT:
185                     container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
186                     break;
187 
188                 case XmlPullParser.START_TAG:
189                     processTag( container, Tag.START );
190                     break;
191 
192                 case XmlPullParser.END_TAG:
193                     processTag( container, Tag.END );
194                     break;
195             }
196 
197             try
198             {
199                 eventType = xpp.next();
200             }
201             catch ( IOException e )
202             {
203                 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
204             }
205         }
206         while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_START_TAG );
207 
208         BatchRequestDsml br = container.getBatchRequest();
209 
210         if ( br != null )
211         {
212             br.setStoreReq( storeMsgInBatchReq );
213         }
214     }
215 
216 
217     /**
218      * Processes the task required in the grammar to the given tag type
219      *
220      * @param container the DSML container
221      * @param tagType the tag type
222      * @throws XmlPullParserException when an error occurs during the parsing
223      */
224     private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
225     {
226         XmlPullParser xpp = container.getParser();
227 
228         String tagName = Strings.toLowerCase( xpp.getName() );
229 
230         GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) );
231 
232         if ( transition != null )
233         {
234             container.setState( transition.getNextState() );
235 
236             if ( transition.hasAction() )
237             {
238                 transition.getAction().action( container );
239             }
240         }
241         else
242         {
243             throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
244         }
245     }
246 
247 
248     /**
249      * Gets the Batch Request or null if the it has not been parsed yet
250      *
251      * @return the Batch Request or null if the it has not been parsed yet
252      */
253     public BatchRequestDsml getBatchRequest()
254     {
255         return container.getBatchRequest();
256     }
257 
258 
259     /**
260      * Gets the next Request or null if there's no more request
261      * @return the next Request or null if there's no more request
262      * @throws XmlPullParserException when an error occurs during the parsing
263      */
264     public DsmlDecorator<? extends Request> getNextRequest() throws XmlPullParserException
265     {
266         if ( container.getBatchRequest() == null )
267         {
268             parseBatchRequest();
269         }
270 
271         XmlPullParser xpp = container.getParser();
272 
273         int eventType = xpp.getEventType();
274         do
275         {
276             while ( eventType == XmlPullParser.TEXT )
277             {
278                 try
279                 {
280                     xpp.next();
281                 }
282                 catch ( IOException e )
283                 {
284                     throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
285                 }
286                 eventType = xpp.getEventType();
287             }
288 
289             switch ( eventType )
290             {
291                 case XmlPullParser.START_DOCUMENT:
292                     container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
293                     break;
294 
295                 case XmlPullParser.END_DOCUMENT:
296                     container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
297                     return null;
298 
299                 case XmlPullParser.START_TAG:
300                     processTag( container, Tag.START );
301                     break;
302 
303                 case XmlPullParser.END_TAG:
304                     processTag( container, Tag.END );
305                     break;
306             }
307 
308             try
309             {
310                 eventType = xpp.next();
311             }
312             catch ( IOException e )
313             {
314                 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null );
315             }
316         }
317         while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_LOOP );
318 
319         return container.getBatchRequest().getCurrentRequest();
320     }
321 
322 
323     /**
324      * Parses all the requests
325      *
326      * @throws XmlPullParserException when an error occurs during the parsing
327      */
328     public void parseAllRequests() throws XmlPullParserException
329     {
330         while ( getNextRequest() != null )
331         {
332             continue;
333         }
334     }
335 }