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 */ 020package org.apache.directory.shared.dsmlv2; 021 022 023import java.io.FileNotFoundException; 024import java.io.FileReader; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.Reader; 028import java.io.StringReader; 029 030import org.apache.directory.shared.dsmlv2.request.BatchRequestDsml; 031import org.apache.directory.shared.dsmlv2.request.Dsmlv2Grammar; 032import org.apache.directory.shared.i18n.I18n; 033import org.apache.directory.shared.ldap.model.message.Request; 034import org.xmlpull.v1.XmlPullParser; 035import org.xmlpull.v1.XmlPullParserException; 036import org.xmlpull.v1.XmlPullParserFactory; 037 038 039/** 040 * This class represents the DSMLv2 Parser. 041 * It can be used to parse a plain DSMLv2 Request input document or the one inside a SOAP envelop. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045public class Dsmlv2Parser 046{ 047 /** The associated DSMLv2 container */ 048 private Dsmlv2Container container; 049 050 /** 051 * flag to indicate if the batch request should maintain a list of all the 052 * operation request objects present in the DSML document. Default is true 053 */ 054 private boolean storeMsgInBatchReq = true; 055 056 057 /** The thread safe DSMLv2 Grammar */ 058 private Dsmlv2Grammar grammar; 059 060 061 /** 062 * Creates a new instance of Dsmlv2Parser. 063 * 064 * @throws XmlPullParserException 065 * if an error occurs while the initialization of the parser 066 */ 067 public Dsmlv2Parser() throws XmlPullParserException 068 { 069 this( true ); 070 } 071 072 /** 073 * 074 * Creates a new instance of Dsmlv2Parser. 075 * 076 * @param storeMsgInBatchReq flag to set if the parsed requests should b stored 077 * @throws XmlPullParserException 078 */ 079 public Dsmlv2Parser( boolean storeMsgInBatchReq ) throws XmlPullParserException 080 { 081 this.storeMsgInBatchReq = storeMsgInBatchReq; 082 083 this.grammar = new Dsmlv2Grammar(); 084 this.container = new Dsmlv2Container( grammar.getLdapCodecService() ); 085 086 this.container.setGrammar( grammar ); 087 088 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 089 factory.setNamespaceAware( true ); 090 XmlPullParser xpp = factory.newPullParser(); 091 092 container.setParser( xpp ); 093 } 094 095 096 /** 097 * Creates a new instance of Dsmlv2Parser. 098 * 099 * @throws XmlPullParserException 100 * if an error occurs while the initialization of the parser 101 */ 102 public Dsmlv2Parser( Dsmlv2Grammar grammar ) throws XmlPullParserException 103 { 104 this.container = new Dsmlv2Container( grammar.getLdapCodecService() ); 105 this.container.setGrammar( grammar ); 106 this.grammar = grammar; 107 108 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 109 factory.setNamespaceAware( true ); 110 XmlPullParser xpp = factory.newPullParser(); 111 112 container.setParser( xpp ); 113 } 114 115 116 /** 117 * Sets the input file the parser is going to parse 118 * 119 * @param fileName 120 * the name of the file 121 * @throws FileNotFoundException 122 * if the file does not exist 123 * @throws XmlPullParserException 124 * if an error occurs in the parser 125 */ 126 public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException 127 { 128 Reader reader = new FileReader( fileName ); 129 container.getParser().setInput( reader ); 130 } 131 132 133 /** 134 * Sets the input stream the parser is going to process 135 * 136 * @param inputStream 137 * contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null) 138 * @param inputEncoding 139 * if not null it MUST be used as encoding for inputStream 140 * @throws XmlPullParserException 141 * if an error occurs in the parser 142 */ 143 public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException 144 { 145 container.getParser().setInput( inputStream, inputEncoding ); 146 } 147 148 149 /** 150 * Sets the input string the parser is going to parse 151 * 152 * @param str 153 * the string the parser is going to parse 154 * @throws XmlPullParserException 155 * if an error occurs in the parser 156 */ 157 public void setInput( String str ) throws XmlPullParserException 158 { 159 container.getParser().setInput( new StringReader( str ) ); 160 } 161 162 163 /** 164 * Launches the parsing on the input 165 * This method will parse the whole DSML document, without considering the flag {@link #storeMsgInBatchReq} 166 * @throws XmlPullParserException 167 * when an unrecoverable error occurs 168 * @throws IOException 169 * when an IO execption occurs 170 */ 171 public void parse() throws XmlPullParserException, IOException 172 { 173 grammar.executeAction( container ); 174 } 175 176 177 /** 178 * Launches the parsing of the Batch Request only 179 * 180 * @throws XmlPullParserException 181 * if an error occurs in the parser 182 */ 183 public void parseBatchRequest() throws XmlPullParserException 184 { 185 XmlPullParser xpp = container.getParser(); 186 187 int eventType = xpp.getEventType(); 188 do 189 { 190 if ( eventType == XmlPullParser.START_DOCUMENT ) 191 { 192 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE ); 193 } 194 else if ( eventType == XmlPullParser.END_DOCUMENT ) 195 { 196 container.setState( Dsmlv2StatesEnum.GRAMMAR_END ); 197 } 198 else if ( eventType == XmlPullParser.START_TAG ) 199 { 200 processTag( container, Tag.START ); 201 } 202 else if ( eventType == XmlPullParser.END_TAG ) 203 { 204 processTag( container, Tag.END ); 205 } 206 try 207 { 208 eventType = xpp.next(); 209 } 210 catch ( IOException e ) 211 { 212 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 213 } 214 } 215 while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_START_TAG ); 216 217 BatchRequestDsml br = container.getBatchRequest(); 218 219 if ( br != null ) 220 { 221 br.setStoreReq( storeMsgInBatchReq ); 222 } 223 } 224 225 226 /** 227 * Processes the task required in the grammar to the given tag type 228 * 229 * @param container 230 * the DSML container 231 * @param tagType 232 * the tag type 233 * @throws XmlPullParserException 234 * when an error occurs during the parsing 235 */ 236 private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException 237 { 238 XmlPullParser xpp = container.getParser(); 239 240 String tagName = xpp.getName().toLowerCase(); 241 242 GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) ); 243 244 if ( transition != null ) 245 { 246 container.setState( transition.getNextState() ); 247 248 if ( transition.hasAction() ) 249 { 250 transition.getAction().action( container ); 251 } 252 } 253 else 254 { 255 throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null ); 256 } 257 } 258 259 260 /** 261 * Gets the Batch Request or null if the it has not been parsed yet 262 * 263 * @return 264 * the Batch Request or null if the it has not been parsed yet 265 */ 266 public BatchRequestDsml getBatchRequest() 267 { 268 return container.getBatchRequest(); 269 } 270 271 272 /** 273 * Gets the next Request or null if there's no more request 274 * @return 275 * the next Request or null if there's no more request 276 * @throws XmlPullParserException 277 * when an error occurs during the parsing 278 */ 279 public DsmlDecorator<? extends Request> getNextRequest() throws XmlPullParserException 280 { 281 if ( container.getBatchRequest() == null ) 282 { 283 parseBatchRequest(); 284 } 285 286 XmlPullParser xpp = container.getParser(); 287 288 int eventType = xpp.getEventType(); 289 do 290 { 291 while ( eventType == XmlPullParser.TEXT ) 292 { 293 try 294 { 295 xpp.next(); 296 } 297 catch ( IOException e ) 298 { 299 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 300 } 301 eventType = xpp.getEventType(); 302 } 303 304 if ( eventType == XmlPullParser.START_DOCUMENT ) 305 { 306 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE ); 307 } 308 else if ( eventType == XmlPullParser.END_DOCUMENT ) 309 { 310 container.setState( Dsmlv2StatesEnum.GRAMMAR_END ); 311 return null; 312 } 313 else if ( eventType == XmlPullParser.START_TAG ) 314 { 315 processTag( container, Tag.START ); 316 } 317 else if ( eventType == XmlPullParser.END_TAG ) 318 { 319 processTag( container, Tag.END ); 320 } 321 try 322 { 323 eventType = xpp.next(); 324 } 325 catch ( IOException e ) 326 { 327 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 328 } 329 } 330 while ( container.getState() != Dsmlv2StatesEnum.BATCHREQUEST_LOOP ); 331 332 return container.getBatchRequest().getCurrentRequest(); 333 } 334 335 336 /** 337 * Parses all the requests 338 * 339 * @throws XmlPullParserException 340 * when an error occurs during the parsing 341 */ 342 public void parseAllRequests() throws XmlPullParserException 343 { 344 while ( getNextRequest() != null ) 345 { 346 continue; 347 } 348 } 349}