001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020
021 package org.apache.directory.shared.dsmlv2;
022
023
024 import java.io.FileNotFoundException;
025 import java.io.FileReader;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.io.Reader;
029 import java.io.StringReader;
030
031 import org.apache.directory.shared.dsmlv2.reponse.BatchResponse;
032 import org.apache.directory.shared.dsmlv2.reponse.Dsmlv2ResponseGrammar;
033 import org.apache.directory.shared.i18n.I18n;
034 import org.apache.directory.shared.ldap.codec.LdapResponseCodec;
035 import org.xmlpull.v1.XmlPullParser;
036 import org.xmlpull.v1.XmlPullParserException;
037 import org.xmlpull.v1.XmlPullParserFactory;
038
039
040 /**
041 * This class represents the DSMLv2 Parser.
042 * It can be used to parse a DSMLv2 Response input.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 * @version $Rev$, $Date$
046 */
047 public class Dsmlv2ResponseParser
048 {
049 /** The associated DSMLv2 container */
050 private Dsmlv2Container container;
051
052
053 /**
054 * Creates a new instance of Dsmlv2ResponseParser.
055 *
056 * @throws XmlPullParserException
057 * if an error occurs while the initialization of the parser
058 */
059 public Dsmlv2ResponseParser() throws XmlPullParserException
060 {
061 this.container = new Dsmlv2Container();
062
063 this.container.setGrammar( Dsmlv2ResponseGrammar.getInstance() );
064
065 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
066 factory.setNamespaceAware( true );
067 XmlPullParser xpp = factory.newPullParser();
068
069 container.setParser( xpp );
070 }
071
072
073 /**
074 * Sets the input string the parser is going to parse
075 *
076 * @param str
077 * the string the parser is going to parse
078 * @throws XmlPullParserException
079 * if an error occurs in the parser
080 */
081 public void setInput( String str ) throws FileNotFoundException, XmlPullParserException
082 {
083 container.getParser().setInput( new StringReader( str ) );
084 }
085
086
087 /**
088 * Sets the input file the parser is going to parse
089 *
090 * @param fileName
091 * the name of the file
092 * @throws FileNotFoundException
093 * if the file does not exist
094 * @throws XmlPullParserException
095 * if an error occurs in the parser
096 */
097 public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException
098 {
099 Reader reader = new FileReader( fileName );
100 container.getParser().setInput( reader );
101 }
102
103
104 /**
105 * Sets the input stream the parser is going to process
106 *
107 * @param inputStream
108 * contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null)
109 * @param inputEncoding
110 * if not null it MUST be used as encoding for inputStream
111 * @throws XmlPullParserException
112 * if an error occurs in the parser
113 */
114 public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
115 {
116 container.getParser().setInput( inputStream, inputEncoding );
117 }
118
119
120 /**
121 * Launches the parsing on the input
122 *
123 * @throws XmlPullParserException
124 * when an unrecoverable error occurs
125 * @throws IOException
126 */
127 public void parse() throws XmlPullParserException, IOException
128 {
129 Dsmlv2ResponseGrammar grammar = Dsmlv2ResponseGrammar.getInstance();
130
131 grammar.executeAction( container );
132 }
133
134
135 /**
136 * Launches the parsing of the Batch Response only
137 *
138 * @throws XmlPullParserException
139 * if an error occurs in the parser
140 */
141 public void parseBatchResponse() throws XmlPullParserException
142 {
143 XmlPullParser xpp = container.getParser();
144
145 int eventType = xpp.getEventType();
146 do
147 {
148 if ( eventType == XmlPullParser.START_DOCUMENT )
149 {
150 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
151 }
152 else if ( eventType == XmlPullParser.END_DOCUMENT )
153 {
154 container.setState( Dsmlv2StatesEnum.END_STATE );
155 }
156 else if ( eventType == XmlPullParser.START_TAG )
157 {
158 processTag( container, Tag.START );
159 }
160 else if ( eventType == XmlPullParser.END_TAG )
161 {
162 processTag( container, Tag.END );
163 }
164 try
165 {
166 eventType = xpp.next();
167 }
168 catch ( IOException e )
169 {
170 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp,
171 null );
172 }
173 }
174 while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
175 }
176
177
178 /**
179 * Processes the task required in the grammar to the given tag type
180 *
181 * @param container
182 * the DSML container
183 * @param tagType
184 * the tag type
185 * @throws XmlPullParserException
186 * when an error occurs during the parsing
187 */
188 private void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
189 {
190 XmlPullParser xpp = container.getParser();
191
192 String tagName = xpp.getName().toLowerCase();
193
194 GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) );
195
196 if ( transition != null )
197 {
198 container.setState( transition.getNextState() );
199
200 if ( transition.hasAction() )
201 {
202 transition.getAction().action( container );
203 }
204 }
205 else
206 {
207 throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
208 }
209 }
210
211
212 /**
213 * Gets the Batch Response or null if the it has not been parsed yet
214 *
215 * @return
216 * the Batch Response or null if the it has not been parsed yet
217 */
218 public BatchResponse getBatchResponse()
219 {
220 return container.getBatchResponse();
221 }
222
223
224 /**
225 * Returns the next Request or null if there's no more request
226 * @return
227 * the next Request or null if there's no more request
228 * @throws XmlPullParserException
229 * when an error occurs during the parsing
230 */
231 public LdapResponseCodec getNextResponse() throws XmlPullParserException
232 {
233 if ( container.getBatchResponse() == null )
234 {
235 parseBatchResponse();
236 }
237
238 XmlPullParser xpp = container.getParser();
239
240 int eventType = xpp.getEventType();
241 do
242 {
243 while ( eventType == XmlPullParser.TEXT )
244 {
245 try
246 {
247 xpp.next();
248 }
249 catch ( IOException e )
250 {
251 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp,
252 null );
253 }
254 eventType = xpp.getEventType();
255 }
256
257 if ( eventType == XmlPullParser.START_DOCUMENT )
258 {
259 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
260 }
261 else if ( eventType == XmlPullParser.END_DOCUMENT )
262 {
263 container.setState( Dsmlv2StatesEnum.END_STATE );
264 return null;
265 }
266 else if ( eventType == XmlPullParser.START_TAG )
267 {
268 processTag( container, Tag.START );
269 }
270 else if ( eventType == XmlPullParser.END_TAG )
271 {
272 processTag( container, Tag.END );
273 }
274 try
275 {
276 eventType = xpp.next();
277 }
278 catch ( IOException e )
279 {
280 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp,
281 null );
282 }
283 }
284 while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP );
285
286 return container.getBatchResponse().getCurrentResponse();
287 }
288
289
290 /**
291 * Parses all the responses
292 *
293 * @throws XmlPullParserException
294 * when an error occurs during the parsing
295 */
296 public void parseAllResponses() throws XmlPullParserException
297 {
298 while ( getNextResponse() != null )
299 {
300 continue;
301 }
302 }
303 }